How to send a JWT from my back-end server to my front-end after Google OAuth2 Authorization flow - authentication

I am creating an application with a React front-end and a Java Spring Boot back-end.
My login flow looks like this:
A user clicks on login on the front end
User is redirected to the Google Oauth authorization endpoint on my server
OAuth 2.0 Authorization flow happens: User is redirected to Google and logs in. Google interacts with my server first exchanging an authorization code and then a JWT access token. My server now has the JWT access token for the user.
ISSUE: I now need to redirect the JWT token to my React front-end so that the token can be saved and used every time the user wants to request access to a protected resource on my server.
Is there now an industry standard/best practice for redirecting the token to my React front-end from the server?
There are similar questions on this subject on Stack Overflow, however they are at least 3 years old, e.g. How to provide frontend with JSON web token after server authentication?
Since then the implicit flow has been deprecated, storing JWTs in local storage is no longer recommended, and https://datatracker.ietf.org/doc/html/rfc6750 explicitly discourages passing bearer tokens to the front end in a redirect URL.
I was wondering if anyone knows of an up to date solution for this problem.

There's a draft IETF BCP for OAuth 2.0 for Browser-Based Apps - see here. Basically, it's very similar to native mobile apps using authorization code with PKCE (proof key for code exchange).
FWIW I agree implicit flow shouldn't be used, but IMO you shouldn't be using authorization code flow without PKCE, as this flow is for server side rendered web apps.
EDIT - Auth0 (one of the most popular CIAM solutions on the market) docs say the same thing - see here.
If the Client is a Single-Page App (SPA), an application running in a
browser using a scripting language like JavaScript, there are two
grant options: the Authorization Code Flow with Proof Key for Code
Exchange (PKCE) and the Implicit Flow with Form Post. For most cases,
we recommend using the Authorization Code Flow with PKCE...

Don't.
You seem to mix 2 issues here.
First, you would like to use OIDC for authentication in your SPA. For this you would use OIDC Implicit Flow or Authorization Code Flow with PKCE.
Second, you would like to delegate authentication to google instead of doing it yourself. Basically this is known as federation - you trust external Identity Provider.
The full-blown version would be to setup your own Identity-Provider server (like e.g. keycloak) and configure federation to google there. Your SPA would initiate OIDC against your Identity Provider and wouldn't even know that google did the authentication. You could also easily add further Identity Providers (e.g. facebook) if necessary.
An easier workaround would be to initiate OIDC login from your SPA directly to Google. This way your SPA would receive token directly from google and you would need to protect your own backend as a resource-server accepting and validating those tokens. Adding further Identity-Providers like facebook would be a challenge.

Related

How to exchange authorization code on backend/API for Mobile OAuth 2.0 federated log in

I currently am working on a mobile app that uses OAuth 2.0 for federated log in with a custom identity provider (not google, facebook, twitter, etc). The larger issue I am attempting to solve revolves around moving the authentication from the implicit grant type, to the authorization code flow grant type with PKCE. This has presented me with a problem that I cannot seem to find a direct answer to:
How do I exchange the authorization code for the user token on the API/backend side?
I cannot exchange the authorization code for the user token on the mobile app as that would be insecure (similar to the current grant type in use).
Is it safe to pass the authorization code to the API through normal API calls and exchange the auth code for the token then? Or, am I supposed to point the redirect URI to the API instead of the mobile app?
Okay, so I am answering my own question as no one else will due to the fact that my question is stupid.
You don't.
You exchange the auth code for the token on the native app. That is secure (as long as you are using PKCE). You need to send the access token to your API/Resource Server to validate against the introspection endpoint. That is how your API can determine if the access request is valid or not.

Questions about Native applications and openId Authorization code flow

I have a few concerns with an OpenId Connect strategy that I would like to use and have been unable to find specifics on what the security concerns may be and any glaring issues with it I am overlooking.
Currently, I have an OpenId Connect implementation using Openiddict with Authorization Code flow. For the client, I have a React-Native app using react-native-app-auth.
I see from other questions on SO and from issues posted on the Openiddict repo that the recommended approach to third-party providers (e.g. Google) is: Client -> Auth server -> Google Auth -> Auth server -> Client/Auth server code and token exchange
However, it seems that a better approach from a UX standpoint (when using a SPA or native app) would be to implement something similar to GoogleSignIn on the client and either handle the identity on the server using an IdToken or authorization code from Google. This introduces an issue as the flow previously recommended could not be used as the entire initial challenge and redirect from Auth server to Google Auth has been skipped.
I have seen that this issue is mitigated by not using the authorization code grant and instead implementing a custom assertion grant. This seems to be an alright approach but would require exposing a custom grant and handling the flow differently on the client and server for local and third-party logins.
My proposed solution continues to use the authorization code flow and instead of adding a custom grant type the client could just pass a third-party identifier "Google" and the token or authorization code in the additional parameters of the OIDC authorize request. The authorize endpoint could then detect the provider and token, perform token validation, create a user or principal from it, and create an authorization code to send back to the client for the code/token exchange. This flow would look like the following:
1. Get the id token from the provider Client -> GoogleSignIn -> Client
2. Pass token to auth server and initiate code / token exchange Client -> Auth Server -> Auth server Verify Google IdToken (JWKS, issuer, audience, provider specific validation, etc...) or exchange auth code -> Auth server -> Client/Auth server code and token exchange
One downside to this approach would be the additional hops to verify the token on the server side. If the token was returned from GoogleSignIn, they themselves said that it could be trusted. https://developers.google.com/identity/protocols/oauth2/openid-connect#obtainuserinfo
I see that it is generally recommended to place the auth server between the client and the third-party but in this process the server is still between the client and auth server but only after the initial exchange from the client and third-party.
Questions,
In general am I missing something with this flow?
In this case would it be necessary to verify the token on the server side?
Is there some better way to approach this that I have completely overlooked?
Am I making this too complicated and UX should not be this much of a concern?
Instead of adding the provider and token to the additional parameters would it make more sense to pass it in the body of a post request? I don't see the issue with passing it via query string but that's also part of the reasoning for the authorization code grant from my understanding.
Apologies in advance for anything I have missed or omitted for brevity that should have been included.
Thanks.
ARCHITECTURE
I'm not sure I understand the UX problem - your existing architecture feels really good. If you want to login directly to Google, just send an acr_values=google query parameter in the authorization redirect, to bypass any authentication selection screens. The exact value will depend on how Openiddict represents the Google authentication option, and some providers use a non-standard parameter such as idp. Have a closer look at the OIDC request parameters.
A key OAuth goal is that the Authorization Server (AS) - Openiddict in your case - shields your apps from all of the provider differences and deals with their nuances and vendor specific behaviour. Your apps then also only receive one type of token, and only ever use simple code. As an example, the Curity AS supports all of these options, none of which requires any code in applications.
APPAUTH AND UX
If a user is already signed in then it can, as you say, look unnatural to spin up the system browser and them it is dismissed immediately.
A common option is to show the consent screen or an interstitial page to keep the user informed - and the user clicks one extra button. This can also be useful for getting password autofill to work. My code example and blog post shows how this might look, though of course you can improve on my basic UX.
OFFLINE ACCESS
I find this term misleading, since refresh tokens are most commonly used when the user is there. Are you just asking how to deal with tokens in a mobile client? Aim for behaviour like this:
Standard messages for API calls with access tokens in an authorization bearer header
Standard refresh token grant messages to refresh access tokens - eg as in this code
Note also that mobile apps can save tokens to encrypted secure mobile storage that is private to the app. This can improve usability, eg by avoiding logins every time the app is restarted. You should think through scenarios such as stolen devices and token lifetimes though.

JHipster - Single Page Application - OAuth2 / OIDC and access token location

Note that I'm quite new with OAuth2 and OpenID Connect so I may be a little bit confused. AFAIK, the recommanded authentication flow with OAuth2 in 2021 is Authorization Code Flow. I have already read the RFC 6749.
I have initialized a project using JHipster (v6.10.5, not the v7) with this configuration:
Which type of application would you like to create? Monolithic application (recommended for simple projects)
Which type of authentication would you like to use? OAuth 2.0 / OIDC Authentication (stateful, works with Keycloak and Okta)
Which Framework would you like to use for the client? React (i.e. a SPA application)
I'm wondering why is the JHipster's implementation stateful? (i.e. using HTTP session cookie JSESSIONID ; access token and refresh token are stored on the backend-side and NOT on the browser-side).
Why don't they make the browser acting as an OAuth 2.0 client to perform the authentication and storing the access token and the refresh token on the browser-side?
I don't find any explanation on the JHispter security page.
Beside, this blog mentions a schema that explains the OIDC Authorization Code Flow with a Public Client / SPA.
To complete Matt Raible comment, from OAuth 2.0 for Browser-Based Apps - draft-ietf-oauth-browser-based-apps-07 and ยง6.1. Browser-Based Apps that Can Share Data with the Resource Server:
[...]
An additional concern with handling access tokens in a browser is that as of the date of this publication, there is no secure storage mechanism where JavaScript code can keep the access token to be later used in an API request. Using an OAuth flow results in the JavaScript code getting an access token, needing to store it somewhere, and then retrieve it to make an API request.
Instead, a more secure design is to use an HTTP-only cookie between the JavaScript application and API so that the JavaScript code can't access the cookie value itself. Additionally, the SameSite cookie attribute can be used to prevent CSRF attacks, or alternatively, the application and API could be written to use anti-CSRF tokens.
[...]
However, I think the use of HTTP-session and OAuth2 token on the backend-side may complexify the management/implementation of some issues as we have to handle different timeouts:
idle timeout for HTTP session between the browser and the backend
expiration timeout or maximum lifetime expiration for the refresh token that is stored on the backend side
...
I'm now wondering how to provide a user-friendly experience, when some borderline cases happen. E.g: when the refresh token has expired on the backend-side but the end-user is still connected as the HTTP session between the browser and the backend is still valid.

Authorization server, Oauth2 and auth0

I have some questions because I don't understand well how implement authentication flow.
Reading some docs I found image below
Now, I understand the access token and refresh token, but I don't think I understand how to implement it.
I have a project where frontend is angular and backend is node.js koa with microservices architecture and gateways in front of them.
I can use auth0 like oauth2 authorization server with users stored inside?
How? In auth0 docs there are tons of instructions and I cannot understand which is right for me.
I have to intercept login, logout and sign up by gateway and redirect to auth0 or I have to do this inside my user microservice?
Does a user table make sense in my project(s) where there are also personal info table and company table?
Is in this way the authorization server sso for all my company projects?
Can I add external company's SSO?
Can I add Google sign in?
You can follow Auth0 Angular Quickstarts to implement your scenario. It exactly shows step by step implementation. https://auth0.com/docs/quickstart/spa/angular2/01-login
From architecture level, you are doing following:
Frontend application (angular) uses auth0-spa-js to implement Authorization Code flow + PKCE to implement login flow. It simply performs user authentication and obtain a token which request API scope as well. To request API permission, add the audience parameter when initiating the login flow.
Once you obtain the token, access token can be used to call your backend API.
In the backend server , you should implement API authorization (It validates the access token and check token have necessary scopes/ permission). https://auth0.com/docs/quickstart/backend/nodejs/01-authorization
Above API authoriazatio quickstart uses express middleware. This blog post explains how to do the same in koa . https://auth0.com/blog/building-and-securing-a-koa-and-angular2-app-with-jwt/
you have a very broad architectural implementation question for your specific organization case.
I would recommend you follow the below user management model which takes care of
Simple API for Authentication, Registration and User Management using NodeJS + Koa + Passport combination.
You can deploy the API to Heroku and test the API using Postman.
You can use the NodeJS Global Error Handler Middleware and you do not have to implement any reduntant local error handler.
As a best practice, use the node JWT middleware that checks the JWT token received in the http request from the client is valid before allowing access to the API, if the token is invalid a "401 Unauthorized" response is sent to the client. This JWT API authorization can be done at your gateway level itself before your microservices.
Finally the Koa + Passport user service contains the core business logic for user authentication and uses Koa-Redis for session management in the node api, it encapsulates all interaction with the mongoose user model and exposes a simple set of methods which are used by the users controller.
Moroever Koa + Passport supports Single sign-on with OpenID and OAuth which answers your other question related to SSO.
Here too you can find that KOA is best suited for microservices as you have already chosen the same. Overlaying authentication + user management using the same infrastructure will prove to be very versatile and extensible.
https://mherman.org/blog/user-authentication-with-passport-and-koa/
In order to connect to an external SSO provider, you could use the nodejs oauth2 client api as follows which allows you to connect your node backend to connect to an external SSO server.
https://www.npmjs.com/package/client-oauth2
For SSO using Google/Gmail, it is best to use SAML based SSO provided by google.
Security Assertion Markup Language (SAML) is an XML-based framework for authentication and authorization between two entities: a Service Provider and an Identity Provider. The Service Provider agrees to trust the Identity Provider to authenticate users. In return, the Identity provider generates an authentication assertion, which indicates that a user has been authenticated.
SAML is a standard single sign-on (SSO) format. Authentication information is exchanged through digitally signed XML documents. It's a complex single sign-on (SSO) implementation that enables seamless authentication, mostly between businesses and enterprises.
below link provides details of how to setup a SAML/SSO service into google from your application.
https://support.google.com/a/answer/6087519?hl=en

Best practice to receive JWT from third party provider?

I am playing with JWT and expressJS to learn something new, and come up with the idea to make my little JWT provider to use for all my future personal projects.
The idea is quite simple, my provider will register with facebook and twitter API, and will use passport to authenticate with them. I will also store users credentials so I don't need to worry about that in my other projects (these project will hold their info about users but various data from socials/passwords etc.. will be in the provider).
I coded this little workflow:
I register the app in my provider with a callback url
Put a button (e.g. 'Login with Twitter') on my project, that links directly to my provider
when I accept the Twitter conditions, twitter callback calls my provider that pick the right user and redirect to my project.
I am stuck on this last point, I would love to pass to my project the JWT token to use for its next requests, but how do I pass to it?
Cannot set cookie because domains are different obviously, I am missing something? Did I follow the wrong way?
The authentication flow you describe is similar to OAuth2. I suggest to read the RFC 6749. It explain the technical details to implement it. You can also refer to OpenID Connect. It is an extension of OAuth2 using JWT
Basically you need to create an access token after a successful login and return a redirection to the callback url. The adapted flow to your context could be the following
App redirects user to central login form
The server prompts user for the credentials :It returns an HTML form with the supported authentication methods, that can include a connection with a third party authentication provider
After a successful authentication, the server creates an access token. It can be a JWT
The server returns a redirection to the provided callback url. It includes an authentication code
The app request the authentication server using the previous code and get an access token
The token can be used by app to access to a protected resource
In Oauth2, the access token it is just a random string, but you can use JWT perfectly.