I have a scenario where I need to implement OAuth 2.0 authorization code flow on the server side - the user authorizes a backend service against Microsoft, the service receives a token, saves it in a database and uses it to perform daily background jobs on the user's data. The token itself is neither needed nor received in the frontend app.
The backend service is an asp.net 5 app with an api and a hosted service. The frontend app only does the initial request to the api, which results in a redirect to Microsoft. The oauth callback url is pointed to the api endpoint which receives the code, gets a token and redirects to the frontend app upon success/failure.
The question is, how to implement state parameter to avoid CSRF attacks and be able to restore some user state in this scenario? E.g. to prevent someone posting some else's code to the callback endpoint. In the usual code flow, the frontend app would generate a state parameter and store it in local storage together with some user state (described here), and compare the state value in the redirect upon returning to the frontend app.
In my case it is the api that needs to generate a state parameter, store it and check it in the callback url. I don't have a user session and the api is load balanced, so I need an external storage, but the solution should be similar. My plan was:
- In the endpoint that redirects to
oauth2login, generate aguidthat acts as the state, - Store it in some external cache as the key with the value of some extra user data (id, name, etc) that the endpoint receives,
- Pass the
guidin thestatequery parameter (?state=asd123) to the redirect url, - In the callback endpoint retrieve the state and check whether such a key exists in the cache,
- If it is, the request is valid and I can use the extra data attached to the key.
All the tutorials I could find deal with the frontend app and local storage, so my idea feels hackish and I wouldn't want to risk when it comes to security by implementing some random algorithms. Do I need to pass that extra user data in state or is it fine to rely on it being present in the cache if the request is valid? Is there a more standard secure way of doing this?
Here is a sequence diagram of the described login flow in case it is helpful:
