Search code examples
authenticationoauth-2.0jwtgoogle-oauth

Passing JWTs securely back to the mobile app frontend after signing in with Google OAuth2


I have a server(API) written in Flask and a client(mobile app) written in React Native. The application allows for logging in with either email/password OR with Google. The Google authentication flow works as such:

  1. User presses on the Sign in with Google button;
  2. Frontend sends the user to the API endpoint /api/google/authorize, which in turn redirects the user to the Google login page where he has to log in and authorize our app to access his account information;
  3. User successfully logged in on the Google page and is now redirected back to our API via the /api/google/callback endpoint;
  4. The callback endpoint exchanges the authorization code sent by Google with an access token and ID token pair. Additionally the user is created if they did not exist up until now.
  5. Now I have to pass this ID token (and a refresh token ultimately) back to the frontend so that further requests made to the API are authenticated/authorized.

The part that I'm having issues with is the last one, where I have to send the tokens back to the frontend in a secure manner. I've read online about what options are there and these are the ones that I kind of considered:

  1. Authorization Code - This would consist of creating a temporary code which then would be exchanged for a token pair in another endpoint, the code would be sent in the query parameters of the redirect back to the app. Unfortunately I don't like the fact that this feels like a duplicate of the OAuth process since during the authentication process I'm using two authorization codes (one from Google and then one generated by my API). Additionally I would have to implement security measures so that not just anyone could use the authorization code issued by my API, but only the frontend/current user.
  2. Custom URI Scheme/Deep Linking - This would consist of having a custom URI scheme like myapp:// instead of https:// and then I would send the tokens as query parameters to the frontend. I tend to go towards this idea more because it feels like its both safe, flexible and does not add a lot of complexity/code. It's just the fact that the frontend would have to add code for listening for this custom URI. Maybe there are downsides to doing it this way that I don't know of?

I would really appreciate if you could tell me if there are other options that I might consider? This is the first time that I'm designing the authentication flow for a mobile app (previously I've only worked on web applications).

Thanks in advance!


Solution

  • Sounds like Step 3 in your flow is the source of confusion (see my comment). But this should help explain why it's an important detail anyways.


    Basically, the server isn't needed in the Authz code OAuth flow. Not that it isn't useful in your use case, though. And sending tokens to/from your backend to the app should be done just as any other API call made from your app. Over https. Be careful with custom uri screens as there's potential for a malicious app to piggy back off of it if not carefully created.

    Since you're presumably using the mobile browser, webviews have security holes and OAuth is a redirect based standard, the user should be redirected back to the app via that browser with the authorization code. Then the app exchanges that with the Authz Server (Google) for the tokens. How your app makes this call should be the same way you make any other API calls from your app. Yes, using https.


    They're are a couple of relevant pieces in your scenario:

    • you have a mobile app
    • you have a server
    • you're using the authorization code flow of OAuth 2.x

    In OAuth 2.x, using the authorization code flow, after the user authorizes access at the Authz Server (Google in this case), the user should be redirected back to the client. Now, in your case, really, the mobile app is the OAuth client. The server is not strictly involved just for the Authz code flow.

    If you had a regular/traditional/server-based web app, the whole server is the OAuth client. The frontend is just how the user interacts with the server based app.

    The line between mobile app and server is different though. The mobile app isn't simply the user agent serving up the app from the server to the user.

    However, Authz code flow alone isn't enough to be secure. Mobile apps are considered public clients. So, pkce needs to be used. There are additional engagements like dpop you can also use, but pkce at min.

    You can use your server to store the tokens though and just keep a session token locally in the mobile app. When tokens are needed, send the session token and retrieve the tokens mapped to that session token.