2

I'm building a multi-tenant system that consists of one (SPA) client, calling multiple API's, all under my control.

User authentication is done with OpenID Connect, I'm sending an ID and access token to the client, the client uses the access token to call the API's.

At this stage, the API's know they receive a request from an authenticated user, but they still need to know what that user can do, the Authorization part.

I would like to prevent the scenario where all my API's call a store where authorization data is persisted, it feels like a performance bottleneck, and would tightly couple all my API's.

I would like to keep my OpenID Connect server as decoupled from this specific project as possible, processing only the users's identity and API scope claims. Therefore, putting all authorization-related claims inside the access token seems like the wrong move.

I came up with the following solution:

  • User navigates to SPA

  • SPA calls OpenID Connect server, gets an access token with identity info

  • SPA calls a custom API endpoint, specific for this project, lets call it 'user-info-api'

  • This API issues a custom JWT token, signed by cert or shared secret

  • This custom JWT token is appended on every subsequent API request, it contains all info needed to do user authorization in each API, therefore eliminating round trips to the authorization store. The only thing the API's need to do is to verify it's signature

I would like a 2nd opinion on this approach for the following reasons:

  • This seems a bit over-engineered
  • I'm worried about the increased payload this would bring to each http request.
  • I'm wondering if there are standardized approaches tackling this same issue
4
  • doesnt your openid connect auth call return a token with claims?
    – Ewan
    Mar 3, 2020 at 15:42
  • Does any of the apis use the same authorization rule as another api? Can't each of the services be responsible for maintaining ACL for Its own resources?
    – slepic
    Mar 3, 2020 at 16:59
  • @Ewan my auth call returns a token with authentication claims, authorization claims are specific for this application and I don't want to pollute my auth token with it Mar 4, 2020 at 7:31
  • @slepic they definitely can, they could all read the authorization data from the datastore and do as they wish with it, but that would make all of them dependent on this datastore. Storing this info in a signed token which I pass around makes the API's less tightly coupled and eliminates multiple roundtrips to the same datastore, whichs seems better (But I could be wrong here, hence my asking) Mar 4, 2020 at 7:36

1 Answer 1

1

Generally speaking with role based auth you are trying to avoid having a configurable permission to role mapping.

The easiest way to achieve this is to have your permissions exactly equivalent to roles. So your authentication provider returns a token with

user : ewan
roles : [User, Editor]

and your app has permissions:

[Authorize(Role=Editor)]

As you note you do generally want to avoid app specific roles such as:

user : ewan
roles : [MeTube.User, MyFaceSpace.Editor]

The recommendation with OpenID Connect is to use a URL prefix to the claims for your app

user : ewan
https://www.MyFaceSpace.com/roles : [Editor]
https://www.MeTube.com/roles : [User]

You can then use 'scope' to request the correct set of claims per application.

Where you control the auth server and apis I would recommend you use this approach rather than adding a second authorisation server or mapping.

I don't think there is a method in the OpenID Connect flow which allows you to get the provider to include extra claims from a second specified provider.

What you can do is create a new token, with the returned claims plus a few more of your own and ask the user to use this for future calls. This is what ASP.Net webpages do, get the token, but then generate a auth cookie which is then used for auth on subsequent requests.

With an API it seems like you will have to get the user to make two auth calls. one for the authentication and a second to get an app specific token with authorisation claims.

1
  • I like your suggestion about returning a second 'enriched' token for the specific app. I'll look further into this, it would certainly use less bandwidth compared to using 2 tokens all the time. Mar 4, 2020 at 13:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.