Choose Authentication for a SPA

When building a SPA there are two alternatives (both uses OpenId Connect protocol) for how to authenticate the users. Traditionally the authentication have been triggered by the end users browser, which means that the tokens are returned to the end users browser and then the token(s) are typically stored on the client. The token are then used when making API calls to the backend.

SPA-triggered-authentication.png SPA-triggered-authentication.png

There are a couple of challenges with this and the biggest one is that there are no real secure way to protected the token in the end users browser (resulting in a larger attack vector). A smaller problem is that the client can’t use a secret against the Identity Provider (if a secret is required, it must be send to the browser and in that case it is not secret anymore).

During the last couple of years the protection and restrictions around cookies have improved a lot and a cookie is therefor a much safer way to handle an authenticated user today. This has evolved a pattern called Backend-for-frontend which makes it possible to use cookies in the end users browser instead of tokens. The backend-for-frontend is just a proxy to the backend API (for example implemented by using YARP, Ocelot or another solution) that identifies the user through the cookie and then exchange the cookie to the corresponding token that is stored on the sever side and finally passes the token to the backend API.

BFF-triggered-authentication.png BFF-triggered-authentication.png

The result of this is that the token is securely stored on the server. To use this pattern, you will trigger the sign-in from the server (as in a traditional web application) instead of doing it from the client, for example before the SPA application is started. After the sign-in is completed the user is redirected (back) to the SPA client.

This is not just a more secure solution, but it is also easier in that it removes all CORS problems and it is typically easier to use refresh tokens on the server side than on the client.