simov / grant

OAuth Proxy
MIT License
4.08k stars 257 forks source link

OAuth 2 state - how can I associate a successful grant with a user id #282

Open fuzing opened 1 year ago

fuzing commented 1 year ago

Greetings, and thank you for your work on this package.

My use case involves allowing users of my website to allow us to access various services of theirs (e.g. google/gmail to send an email on their behalf). I have been utilizing my own hacked solution until now, and I was passing the "userId" of the currently logged in user as the OAuth2 "state" parameter. Upon receipt of the granted tokens I'd grab the userId off the state and make the association between the grant and the user for my DB.

I'm using next-js and hence am utilizing the vercel handler. I'm not seeing an obvious mechanism to do this - would you mind providing some clues.

Also, given that the vercel handler seems to use a single store/Session(), is there an issue with overlapping oauth requests between multiple users?

Thank you in advance for any insights

simov commented 1 year ago

You can configure the profile response option to get the user profile as well. After that it all depends on your setup, and you can take a look at the 4 main examples in that repo, but maybe the easiest to set up and understand is the transport-state one. Inside the response key in that code snippet you will get the access/refresh/id tokens + the user profile. Then you can store that in a database, redirect the user somewhere else and so on.

The session implementation generates unique identifier for each authorization attempt, so collisions are not possible. Though note that for serverless handlers the in-memory session store is being used by default unless you specify your own session store implementation (Firebase example). Depending on your overall setup using the default in-memory session store may potentially leak data into the user's browser agent.

fuzing commented 1 year ago

Thank you - I'll digest and implement - cheers!

fuzing commented 1 year ago

Sorry to bother. Given that I know the user's Id when I start the OAuth flow, is there a way to add this to the session/state prior to starting the flow? (and then retrieving upon completion). I don't use any of the provider's profile info.

simov commented 1 year ago

Any parameter sent as query string to the connect endpoint, or url encoded form body in case you are using a POST request, will end up being stored in your session under the grant.dynamic key.

Then you may want to read those custom parameters after the OAuth flow is complete:

module.exports = async (req, res) => {
  var {response, session} = await grant(req, res)
  if (response) {
    var obj = await session.get()
    // obj.grant.dynamic will contain your custom parameters
  }
}

After reading the user identifier from the session you can add it as query string parameter to the rest of the response parameters and redirect the user back to your app, or do something else depending on your use case.

fuzing commented 1 year ago

Makes perfect sense. Thank you.