Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Google Sign-In with Backend Verification Flow Clarification

I've spent hours trawling through various tutorials and articles and am finally giving in to asking.

I want to enforce the use of Google Sign-In authentication for all users of my Angular 7 application. However, once Google authentication is complete, I want to first check that the user exists in my back-end DB (PostgreSQL). If they do, then I want to issue a JWT for two purposes:

  1. Ensure that future calls to my Spring Boot REST services are only fulfilled for authorized users.
  2. Protect my Angular routes using an AuthGuard that is aware of the token.

So far, I have been able to retrieve the id_token from the gapi auth2 auth response and forward it to my Spring Boot POST mapping, but I'm struggling to pin down exactly which OAuth 2.0/OpenId flows/grants I'm aiming for which is making life difficult when sourcing appropriate Spring Boot documentation/tutorials.

Is anyone able to clarify which flow/grant I should be aiming for and whether or not my current direction is valid?

like image 604
ggle Avatar asked May 24 '19 13:05

ggle


People also ask

Does Google sign in use JWT?

The JWT ID Token is only needed during Sign-in. We just need to validate it once during Sign-in like so: client. verifyIdToken({idToken: token, audience: CLIENT_ID}) . The ID Token is not used to Authenticate a user to My Web App.

What is Id_token Google OAuth?

The id_token is used in OpenID Connect protocol, where the user is authenticated as well as authorized. (There's an important distinction between authentication and authorization.) You will get id_token and access_token. The id_token value contains the information about the user's authentication.


1 Answers

I suggest you to implement a “stateless” authentication system, coupled with Google Sign-in ID provider.

“Using a JWT as a bearer for authorization, you can statelessly verify if the user is authenticated by simply checking if the expiration in the payload hasn’t expired and if the signature is valid.” — Jonatan Nilsson

Some good resources on the subject :

  • https://www.jbspeakr.cc/purpose-jwt-stateless-authentication/
  • https://auth0.com/blog/stateless-auth-for-stateful-minds/

The general idea is :

  • frontend retrieves a Google Sign-in authentication JWT token.
  • frontend sends JWT token with each HTTP request (with authorization header)
  • backend retrieves JWT for each request, validates its signature, and gets payload attributes (email, id…)
  • then, backend checks ‘email’ or ‘id’ in users database to allow or not request.

Backend is stateless, and simple to implement. This design tends to become a good practice in cloud platform, and for instance, Google Cloud is using this a lot in its new products : Cloud Run

Some details on each step:

1) frontend retrieves a Google Sign-in authentication JWT token.

To do that, you can use Google Sign-in library directly or use ng-gapi to manage Google Sign-In in Angular.

2) Each http call to backend has an authorization header with JWT token (id_token) retrieved from Google Sign-in.

You can use an HttpInterceptor for that.

headers: {
  Authorization: Bearer ___JWT ID TOKEN___
}

See Top 10 ways to use Interceptors in Angular from Michael Karén.

Pay attention, to not store the Google JWT Id_token in variable. It could be refreshed if expired (automatically done by Google Sign-in), so you should take a fresh version each time you use it inside HttpInterceptor.

3) Implement a filter inside Spring Boot

For each request, this security filter will retrieve JWT ID TOKEN and validate it with Google library.

NetHttpTransport transport = new NetHttpTransport();
JsonFactory jsonFactory = new GsonFactory();

GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder(transport, jsonFactory)
  .setAudience(Collections.singletonList(clientId))
  .build();

GoogleIdToken idToken = GoogleIdToken.parse(verifier.getJsonFactory(), token);
boolean tokenIsValid = (idToken != null) && verifier.verify(idToken);

if (tokenIsValid) {
  GoogleIdToken.Payload payload = idToken.getPayload();

  // Get profile information from payload
  payload.getEmail())...
...

But be careful, to not create a GoogleIdTokenVerifier for each request, use factory pattern. This class will retrieve certificates and cache them automatically, to avoid useless request to google servers.

Some resources : Google Sign-in, Authenticate with a backend server

like image 62
Thierry Falvo Avatar answered Oct 17 '22 07:10

Thierry Falvo