Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Which OAuth2 authentication flow shoud I use for PWA + server side application

I am trying to choose the right authentication flow for an application:

  • Fontend is an Progressive Web App accessible only via HTTPS. It'is done in Angular, Single Page Application.
  • External Authorization Server
  • Backend accessible via REST calls

For now I am using Authorization Code Grant flow.

What have I tried:

  • I've checked official site. There is a list of possible flows (Authorization Code, Implicit, Password, Client Credentials, Device Code, ...), but no clear indication how to choose between them.
  • Then I found this excellent article on Auth0.com. Unfortunately PWA + server side beckend is not present in their scheme.

Could you please tell me what OAuth2 flow is appropriate to my context and why?

like image 608
Maksym Demidas Avatar asked Jan 28 '23 09:01

Maksym Demidas


1 Answers

Assumptions (the way I understood the question):

  • You own and develop both frontend (Angular app) and backend (server-side REST API).
  • You want to outsource authentication to a 3rd party identity provider.
  • You want the Angular app (Client) to hold the token and be able to authenticate on the backend (Resource Server), with the identity of your user (Resource Owner) established on the 3rd party (Authorisation Server / Identity Provider (IdP) ).

First, a sidetrack. For this use-case, OpenId Connect (OIDC) would be a better fit, because that supports the identity element. The point in OAuth2 is to authorize your app to do stuff on the 3rd party. What you want is establish the identity of your user, with the help of the 3rd party, and that's what OpenId Connect does.

Ok, so which flow (OIDC is still based on OAuth2).

The first questions are whether the Client is trusted to do anything on the Resource Server, and whether it can securely store a secret. This is clearly not the case, a client-side app is not trusted, and cannot hold a secret. In the client credentials flow, the client uses a secret to authenticate on the IdP to receive a token for the resource server. This would mean your Angular app stores a password which it uses to get a token for your backend, clearly not what you want.

Resource owner password credentials flow is used when the client is trusted to handle user credentials. In your use-case this is not good, because practically it would mean your Angular app would get the users password to forward it to the IdP in exchange for a token. Your Client should not have access to the user password, it is not trusted.

Now comes the more interesting part.

The question is whether your Client has a server-side to securely hold a secret. If it does, Authorization Code Grant is good, because it allows your user to authenticate on the IdP, get redirected back with an authorization code, and the server-side can then exchange that for an access token to be used on the resource server. However, your Client in this scenario does not have a server-side, as far as I can understand the API is the resource server. So this is not good for you, because it needs a client secret, and you can't store it in your Angular app.

And this pretty much leaves you with the Implicit Flow, for which you don't need a client secret, but on the other hand it's difficult to do things like refresh tokens. In the flowchart you linked to, the last question is whether your Client is an SPA - and in your case it is, so you should go for the implicit flow by default.

This is probably the most secure model for you, because even in case of a compromise of your Client, your user credentials are still safe (the Angular app never has access).

However, you can model this whole thing differently, and that simplifies it quite a bit.

As far as I could understand, you own both the Client and the Resource Server, and the Resource Owner is using the Client, you just want to offload authentication while you still manage users in a 3rd party service.

Looking at it this way, your Client is trusted to access user credentials, and the user using it is the Resource Owner. So you could use the Resource Owner Password Flow, where the user enters his credentials directly into the Angular app, which goes to the IdP, gets a token, and Angular simply uses that to access stuff on the API (Resource Server).

The risk compared to the Implicit Flow is that if the Angular app is compromised, user credentials will be disclosed to the attacker. Whether you want to accept this risk entirely depends on you. Note that this would obviously not work if the IdP is a well-known service (like a social website for example), because as your user I wouldn't want to give my social site password to your app. But as long as you manage users anyway, it can be acceptable to trust the Client.

like image 124
Gabor Lengyel Avatar answered Feb 05 '23 17:02

Gabor Lengyel