Google Sign-In with Backend Verification Flow Clarification
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