DEV Community

Cover image for NestJS Authentication with OAuth2.0: Adding External Providers

NestJS Authentication with OAuth2.0: Adding External Providers

Afonso Barracha on April 14, 2023

Series Intro This series will cover the full implementation of OAuth2.0 Authentication in NestJS for the following types of APIs: Exp...
Collapse
 
enzo_friasborda_c9426764 profile image
Enzo Frias Borda

Hi, excellent article, it helped me a lot!
I have a question...
Is this flow still recommended or is it better for the backend to just redirect with the code, then the front end in another call to the API with the code asks for the access token so that the token does not travel in the URL?

Collapse
 
tugascript profile image
Afonso Barracha • Edited

So this is outdated, and for the upcoming OAuth 2.1 standard you shouldn't use the implicit flow.

I may have to revisit these articles and fix a lot of the recommendations.

Collapse
 
tugascript profile image
Afonso Barracha

In hingsight I should've followed standards more, but I cut some corners since it was purely educational

Collapse
 
enzo_friasborda_c9426764 profile image
Enzo Frias Borda

Thank you very much for the quick response!

Just to confirm, the flow should be:

  1. Frontend: generate code_verifier and code_challenge, call Nest to get the authorization URL, and Nest redirects the user to Google using the frontend's code_challenge.
  2. The user logs into a provider's account.
  3. The provider redirects to the backend with the code.
  4. The backend redirects to the frontend using the URL with a code generated in the backend !== provider_code.
  5. The frontend executes the post method to the backend with the code and the code_verifier.
  6. The backend passes the code_verifier to Google to generate the token and retrieve the data.
  7. The backend responds with its own token and everything else?
Thread Thread
 
tugascript profile image
Afonso Barracha

Personally since the call to google is made by the server, I keep them separate. I normally do something like this in production:

  1. Front-end: generates code_verifier, code_challenge and state, caches the code_verifier and state in localstorage (web) or secure storage (native);
  2. Pass google as a client_id query parameters instead of the url params, this will allow you to add Dynamic Registration in the future, which is used in the new Model Context Protocol server apps (if AI is something important in your company);
  3. On the IDP server you generate a new state, code_verifier and code_challenge, make sure to use S256 if you want extra security. Cache both the user state and the server state, with all the user code_challenge and the IDP code_verifier. I normally use the IDP state as the Key;
  4. With the server state and code_challenge call google;
  5. On the server callback check the state, and call token endpoint with the server code_verifier;
  6. Cache the user data and generate a code (remeber to hash it with SHA256 or HMAC SHA256) and cache it, returning the plain text code and the current user state in the FOUND redirect. I normally use two Base62 uuids joined by a hyphen as the code, sha256 each part, I use the first UUID as the cache key.
  7. The front-end gets the code, checks the state, then calls the server token endpoint with the code and the code_verifier.
  8. The server does the code exchange, uses the user data to create or retreive a user from the persistant DB.
  9. The server returns to the front-end the access and refresh tokens.
Thread Thread
 
enzo_friasborda_c9426764 profile image
Enzo Frias Borda

Thank you so much again!

Collapse
 
tugascript profile image
Afonso Barracha

Just noticed this morning there was a major bug on the tutorial, just fixed it after one year, sorry for the inconvenience.

I left the state static, but it actually should be cached and new on every request

Collapse
 
samihk profile image
Abdul Sami Haroon

thanks a ton, this have been super helpful, I've been looking to work on a POC with fastify + external authentication and this has done the job for me.
Also the code quality is super!

much love <3

Collapse
 
Sloan, the sloth mascot
Comment deleted
Collapse
 
tugascript profile image
Afonso Barracha

The way it is set up, if the user does not exists it will just create a new account with the external provider. You could add a third and forth endpoints for registration if you deem that as necessary.

Collapse
 
galentino profile image
Edric Galentino

You are hero bro. Thanks a lot