Authorization and Authentication in microservices - the good way

Viewed 1100

I'm considering a microservice architecture and I'm struggle with authorization and authentication. I found a lot of resources about oauth2 and openid connect that claim they solve the issue but it is not clear enough for me.

Let's consider we have a following architecture:

enter image description here

In my system I want to add a feature only for a certain group of users defined by role. I want to also know the name of the user, their email and id.

After my research I find the following solution to be a good start:

  1. SPA application displays login form.
  2. User fills in the form and sends POST request to authN&authZ server.
  3. The server replies with access token (being a JWT) that contains name, email, id and role of the user. The response contains a refresh token as well.
  4. SPA application stores the token and attaches it to every request it makes.
  5. Microservice 1 and Microservice 2 check if the token is valid. If so, they check if the role is correct. If so, they take user info and process the request.

How far away from the good solution I am? The login flow looks like Implicit flow with form post described here but with implicit consents and I'm not sure if it's fine.

Moving forward, I find passing user data in JWT (such as name, email) to be not a good solution as it exposes sensitive data. I found resources that say it is recommended to expose only a reference to a user in token (such as ID) and replace such token with a classic access_token in reverser-proxy/api gateway when sending a request to a microservice. Considering such solution I think that following scenario is a good start:

  1. SPA application displays login form.
  2. User fills in the form and sends POST request to authN&authZ server.
  3. The server replies with access token and refresh token. API gateway (in middle) replaces access token with ID token and stores claims from access token within its cache.
  4. SPA application stores the token and attaches it to every request it makes.
  5. Handling a request, API Gateway takes ID Token and based on the user ID generates a new access token. The access token is send to microservice 1 or microservice 2 that validate it as previous.

How do you find such solutions? Is this a secure approach? What should I improve proposed flow?

Thanks in advance!

2 Answers

You are on the right tracks:

ZERO TRUST

This is an emerging trend, where each microservice validates a JWT using a library - see this article. JWT validation is fast and designed to scale.

CONFIDENTIAL TOKENS FOR CLIENTS

Internet clients should not be able to read claims that APIs use. The swapping tokens in a gateway concept is correct, but the usual approach is to issue opaque access tokens here, rather than using ID tokens. At Curity we call this the Phantom Token Approach.

SECURE COOKIES IN THE BROWSER

One area to be careful about is using tokens in the browser. These days SameSite=strict HTTP Only cookies are preferred. This requires a more complex flow though. See the SPA Best Practices for some recommendations on security.

SPAs should use the code flow by the way - aim to avoid the implicit flow, since it can leak tokens in the browser history or web server logs.

SUMMARY

All of the above are general security design patterns to aim for, regardless of your Authorization Server, though of course it is common to get there one step at a time.

Don't use your own login form. As Garry Archer wrote, use the auth code flow with PKCE which is the recomended flow for applications running in a browser.

If you don't want to get an ID token, don't ask for the openid scope in the initial auth request. The type of issued access tokens (JWT or opaque) can often be configured on your OAuth2 server. So I see no need to issue new tokens at your gateway. Having more token issuers opens more ways of attacking your system.

Your backend modules can use the userinfo endpoint, which will give them info about the user and validate the token. This way, if the token was invalidated (e.g. user logged out), the request processing will not proceed. If you validate just a JWT signature, you will not know about the token being invalidated.

If you plan to make requests between your backend modules as part of of a user request processing, you can use the original access token received from your SPA as long as your modules are in a safe environment (e.g. one Kubernates).

Related