0

I've a React JS app, which makes this request to my back-end API. i.e

window.location = "https://my-server.com" + "/gmail/add_account";

cannot set HTTP headers for window.location see this this server endpoint redirects to Google OAuth page, which returns a response to my redirect_uri.

def add_account
  # no auth headers sent here, because front-end has used window.location
  gmail_service = GmailService.new
  session[:uid] = params["uid"]
  redirect_to gmail_service.generate_authorization_url()
end

def oauth_postback
  # session object is {} here
  # Since there are no authorization headers, I cannot identify my app's user
  # How can I identify my app's user here?
end

The problem I'm facing is that when the OAuth flow sends the response to my redirect_uri it does not return include any authorization header, due to which I'm unable to identify which user of my app has launched this OAuth flow.
I've tried setting up a session variable in the /gmail/add_account endpoint, which works fine. After this endpoint redirects to the OAuth screen, and the Oauth flow sends a response to my Oauth redirect_uri, there my session object is {}.
How can I implement this flow such that I know which user has launched this OAuth flow?

Masroor
  • 1,484
  • 3
  • 14
  • 23

1 Answers1

1

You have basically two options:

  • the state parameter

    The state parameter is part of the OAuth2 spec (and is supported by Google). It's a random string of characters that you add to the authorization URL (as a query parameter), and will be included when the user is redirected back to your site (as a query parameter). It's used for CSRF protection, and can also be used to identify a user. Be sure that if you use it, it's a one-time value (e.g. a random value that you store in your db, not the user's ID).

  • sessions with cookies

    If the user has previously logged in, you should be able to identify them by their session cookie. It sounds like this is the approach you're currently taking, but the session is getting reset.

    It's difficult to debug this without knowing more about your stack/code, but a good first step would be just trying to load your callback URL without the redirection to Google to see the session object is still empty. If so, that would indicate an issue with how you've implemented sessions generally and not something specific to this flow.

    As a note, based on the code you've shared, I'm not sure how params["uid"] is getting set if you're doing a redirect without any query parameters or path parameters.

Finally, you may consider using a managed OAuth service for something like this, like Xkit, where I work. If you have a logged in user, you can use Xkit to connect to the user's Gmail account with one line of code, and retrieve their (always refreshed) access tokens anywhere else in your stack (backend, frontend, cloud functions) with one API call.

Trey Griffith
  • 499
  • 4
  • 8
  • I'm not using sessions for authentication, but [devise_token_auth gem](https://github.com/lynndylanhurley/devise_token_auth). The OAuth `state` sounds reasonable to be used in this scenario. Thanks for pointing it out. – Masroor Nov 10 '20 at 18:48