OAuth2 flow in full-stack NestJS application - express

Yet another OAuth2 question that isn't quite covered elsewhere.
I'm using NestJS backend, React frontend, Passport and my own DB for authentication. Trying to add an
OAuth2 identity provider (Google).
I configured my NestJS app as an OAuth Client. After logging in I'm receiving the callback at which point I have an access_token and the requested user details extracted from the payload of the id_token. This is encapsulated in a class extending PassportStrategy(Strategy, 'google') and an AuthGuard('google') and much of it is handled automatically. Code here.
At this point however, I need to maintain an authenticated session between backend (NestJS) and frontend (React). I suppose I need a JWT, but I'm wondering about the best approach:
Can I use a token provided by the IdP (e.g. id_token or access_token)? So that I don't have to worry about issuing tokens myself. I.e. the frontend receives the token (either from backend, or the IdP directly), sends it on every request, backend verifies it with the IdP on every request (verifyIdToken or getTokenInfo of google-auth-library).
One drawback here is the extra network request every time. I'm not sure if there's a need for that because the IdP is only used to identify the user, not for access to other resources. Another drawback is that I need to store a refresh token and handle when the token expires (get new one, update it on the frontend).
So alternatively, could I just issue a JWT myself and not worry about checking in with the IdP? Once the JWT expires I'd need to prompt the user to log in again. In this case, I wouldn't need to store the IdP tokens. But is this good practice? One issue I can think of is that I won't detect if the user revokes access in the IdP (until the JWT expires).

I ended up issuing my own JWT tokens and managing User sessions in my app, as described in this article: OAuth2 in NestJS for Social Login (Google, Facebook, Twitter, etc)

probably my solution would be helpful.
you could access complete source code of my app that implemented with react typescript (redux toolkit rtk Query) and nestjs included of google oauth2 flow with passport.js. resource

Related

Who generates JWT when using Google OpenID Connect authnentication for my ASP.NET Core Web API app?

I am building an ASP.NET Core 6 Web API application for mobile clients (and maybe later SPA JS app). The application should have sign-in with Google option. I also want to add my own app's custom sign up and sign in options that would also be based on JWT authentication and not cookie.
I understand that for my custom sign in flow my app will generated JWT that will be sent to the client.
But I have few questions how that works when user signs-in with its Google account:
who's responsibility is to generate the JWT when user signs-in with its Google account? Is that responsibility of Google or mine application? I don't want Google to return JWT to the client in the cookie.
Then when client is authenticated with Google, and sends requests to my application, how can my application validate JWT token it gets?
When user signs in with Google for the first time, should I automatically register that user in my application (I am using Identity framework) by taking claim values (email) from the JWT? What is the general practice here?
I am trying to understand these processes and flows so sample code is not necessary (but I do welcome it).
Ad.1. Normally, in a larger system, you would have an authorization server (AS) that would handle user authentication and the issuance of tokens. Your clients would contact only the AS, and the AS will be able to provide the user with different forms of authentication: e.g., through your website's password or through Google. The AS is the single point of issuing tokens to your clients. It can issue tokens regardless of the authentication method used. So it then doesn't matter whether the user authenticated with Google or a password, the client will still get the same access token.
Ad.2. When the AS issues token to your client, then you don't have any problems validating that token. The client doesn't care if the user authenticated with Google or not, it's not relevant in this case.
If you decide to skip using an AS and let the client receive tokens directly from Google, then you can still verify them. An ID token is a JWT and can be easily validated with a JWT library using verification keys provided by Google. Access tokens returned by Google are opaque tokens (If I remember correctly), and you need to check whether Google exposes an endpoint to verify them.
Ad.3. That is the general practice. When the user authenticates with Google and you notice that you don't have that user's data in your system, then you take the information from Google's ID token and create a user entry in your system.

When an Oauth provider is used to delegate authentication, then does the appserver return any token to the caller?

In Oauth and Openidconnect, the appserver endpoint invocation starts the Oauth flow and the app server gets the token from the auth server and is able to pass the token to resource server to access resources (delegation) on behalf of the resource owner.
The token exchange happens between the app server and resource server, and the token never arrives at the end users browser.
I'm working on a web api (aka app server) that will be consumed by a mobile app. There is no other server involved. Presently the login endpoint returns a signed JWT token to the user if correct credentials are supplied (validate against the db). User places this token in the header of the subsequent request.
Assuming I don't want to have a user db and validate logins, and instead delegate the auth check to another service like azure b2c or firebase (that use the Oauth), then I assume the flow is like given below:
Api registered the firebase/azure b2c (let's call this the provier) clientid, secret.
User invokes login endpoint of my api
The api invokes the provider's Oauth flow.
User gets popup to authenticate with the provider.
Eventually the provider will send the token (containing the claim like username) to the api (aka app server)
Does the user get back any token? Otherwise, when the user makes subsequent endpoint calls, then how is the endpoint able to identify who is this user and whether he is already authenticated?
Although it is okay to send back the access token to the user , but from the security best practise 's point of view , it is better not to do it which I quote the reasons as follow from this:
Because of the issues outlined above, the best security recommendation
for an SPA is to avoid keeping tokens in the browser at all. This can
be achieved with the help of a lightweight back-end component, often
described as a Backend-For-Frontend.
The backend component can then be configured as a confidential OAuth
client and used to keep tokens away from the browser. It can either be
stateful and keep tokens in custom storage, or stateless and store the
tokens in encrypted HTTP-only, same-site cookies. Whichever variant is
chosen, the backend component creates a session for the SPA, using
HTTP-only, secure, same-site cookies, thus enabling a high level of
security. Such cookies cannot be read by scripts and are limited to
the domain of the SPA. When combined with strict Content Security
Policy headers, such architecture can provide a robust protection
against stealing tokens
Also from here ,they suggest for mobile app 's OAuth2 best practise , it should perform the OAuth flow inside a system browser component.

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

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.

Single Signon Tokens usage in multiple applications

I am currently working on a small SingleSignon application. This way, I can save time whenever i make a new project, because the login process is mostly in place from the beginning.
To start with i think I should mention that many off my applications are build on Angular, so I often have multiple applications in one project:
The Angular app (HTML / Javascript)
The REST API (Either PHP or .NET (doesnt really matter))
I have been reading up on OAuth2, JWT and so on, and I understand that:
1) the application authorizes with the SSO API.
2) the SSO API responds (if successful) with an access token.
3) Add the access token to the header, and i have now access to the SSO APIs
BUT
What about my own API that belongs to the application itself? (See the image below for better understanding).
The API for the application knows nothing about the token I recieved from the SSO API, and would of course reject it...
SingleSignon Authorization flow
How would you normally implement this?
Should the application API also ask the SSO api on every request, to validate the token, or how? What would be best practice?`
Thanks
/Dennis
After studying Auth0, I found out that if you are using Opaque tokens (croptographically random string, with no meaning), the token is being verified against the authorization server from the API, as I mentioned in my original post. If you are using JsonWebToken on the other hand, there is no need to contact the authorization server, but check validity of the token by its expiration and signature, AND audience should match the domain of the custom API
So therefore; If you have a custom resource / API, you can benefit from a selfsigned token like JWT, and define the custom resource url in the AUD grant of the token.
Then the resource can validate against the AUD grant.

OpenId Connect renew access_token in SPA

Trying to implement OpenId Connect in Web Application consisting of following components
Identity Provider
Resource server
Single Page Application acting as Client.
Identity Provider and Resource Server are the same application.
SPA use Password Flow to get access_token and stores into the cookie. Storing access_token into cookie has it's security threads, but's it's a different story.
Problem
access_token issued by IdP is expired after 30 min and SPA needs to renew token without asking users for credentials again.
Solution
IdP returns refresh_token along with access_token. Whenever SPA gets 401 from Resource Server, it sends refresh_token to IdP and get's new access_token back.
Problem
Sending refresh_token to SPA is bad practice.
A Single Page Application (normally implementing Implicit Grant) should not under any circumstances get a Refresh Token. The reason for that is the sensitivity of this piece of information. You can think of it as user credentials since a Refresh Token allows a user to remain authenticated essentially forever. Therefore you cannot have this information in a browser, it must be stored securely.
Suggested solution
When the Access Token has expired, silent authentication can be used to retrieve a new one without user interaction, assuming the user's SSO session has not expired.
I think Silent Authentication is not applicable to Password Flow when IdP and Resource Server is same application. access_token issued by IdP is only piece of information which can be used to authorize against Resource Server/IdP after its expiration, how a client can convince IdP to issue new access_token? (without sending refresh_token)
Found angular-oauth2-oidc library which uses refresh_token to renew access_token.
What is best practice/solution in this case to renew access_token?
technical details
Identity Provider - ASP.NET Core + Openiddict library.
SPA - AngularJs application.
Single page applications must not receive refresh tokens. That has been established rules in OAuth 2.0 and OpenID Connect.
One good option I see here is to use Implicit Flow. This will establish a front channel session from your browser to Identity Provider. With password grant type you do a back-channel call (POST), so you don't get such session.
Usually this is a cookie which points to information about previous logged in status (these are identity provider specifics). With completion of the flow, SPA will receive the access token. As you figured out, it will expire. But once that happens, SPA can trigger another implicit flow, but this time with prompt query parameter.
prompt
Space delimited, case sensitive list of ASCII string values that
specifies whether the Authorization Server prompts the End-User for
reauthentication and consent. The defined values are: none , login, consent and select_account
If you identity provider maintain a long lived session (ex:- few hours or days) or if it maintain a remember me cookie, SPA could use prompt=none making it to skip login step from identity provider. Basically, you are getting browser based SSO behaviour with this.
Using the Resource Owner Password Credentials flow defeats the refresh token storage argument: instead of not being able to store the refresh token in a secure place, the SPA would now have to store the Resource Owner credentials in a secure place (assuming you want to avoid requesting username/password from the user frequently). The Implicit grant was designed for usage with an SPA, so it is better to stick with that.
Further to previous answers, the latest OAuth working group guidance for SPAs no longer recommends use of the implicit flow.
If you have simple, shared domain app (IdP, RS and client on a single domain) then you should consider not using OAuth at all. From the doc:
OAuth and OpenID Connect provide very little benefit in this
deployment scenario, so it is recommended to reconsider whether you
need OAuth or OpenID Connect at all in this case. Session
authentication has the benefit of having fewer moving parts and fewer
attack vectors. OAuth and OpenID Connect were created primarily for
third-party or federated access to APIs, so may not be the best
solution in a same-domain scenario.
If you are using OIDC/OAuth in a SPA, they recommend the auth code flow with PKCE.