We have started on some integration with Auth0 that allows a user to login to our single-page web application, and the web application to receive a token which it uses to communicate with our API. We have multiple tenants in our system and have created a client for each tenant in our account.
The challenge we are facing now is introducing the possibility of some of our tenants to call our API from their systems to create new users associated with them. More generally we are considering how to do the authentication in our APIs; so it can handle being called from our web application, from our tenants back-end systems or a third party in the future. Below are a few more details on the scenarios.
From reading similar posts on the forums it seems there are a few different approaches and that Auth0 may not offer any specific support for API keys. But I’m still a bit in doubt about what to choose. It would be really great if we can get different approaches described and some official recommendations on which approach to choose in different scenarios. I’ll be happy to offer more details for our specific scenario if needed.
Our own single-page web application
- In our own web application we have the user log in on a specific version of the web application that determines the client being used (the client ID send to Auth0).
- The login will generate a token (JWT) for the user, with some custom data from the app_metadata; our own ID of the tenant and the user along with some roles.
- When the web application sends requests to the API, we will validate the token (JWT) and extract the information about the user, tenant and roles.
- The API performs some authorization based on the roles as well as the user and tenant.
Tenants
- We are thinking to givem them an API key that they can use to call most parts of our API.
- There are some parts of the API that is not for a specific user and not used by the web application.
- Some of this is an API that relays request on to Auth0’s user management API to lookup and perform operations on users belonging to the tenant.
- There will also be some APIs that do not relay on to Auth0, but still offers operations regardless of any users or across all users.
Third parties
- We are not really considering these yet
- However, we think these will work on behalf of a specific user (and like the social identity providers require some consent first).
In general there is nothing wrong and it’s even pretty usual to have an API accept different methods of authentication. This is even supported at the HTTP level where there’s specific headers WWW-Authenticate
that the API can use to signal the available methods for authentication.
Based on the description you provided the access to the API that happens as a consequence of a end-user action in one of your client application would use JWT bearer tokens to authenticate the request to the API. This is in widespread use and you also seem to have that part nailed down so lets focus on the other type of access.
The second access type you describe is one where there is no need for a direct relationship to a specific user. I don’t have any data to back this, but the API Keys approach is possibly the most common way to authenticate this type of access.
You mention that from your understanding Auth0 does not support API Keys and I would say it’s partially true. Although there is no direct support for API Keys, we do support OAuth2 client credentials grants. This grant type is specifically aimed at applications that want to access an API on behalf of themselves instead of an end-user. The way they do this is by exchanging a client identifier and client secret for a token that could be used against the API.
With this functionality, you can implement tenant-level access to your API that is pretty much equivalent to API Keys. The only difference is that client credentials imply that the calling party has to make an intermediate request to exchange client identifier and secret for the token that it would use to call the API.
However, if you don’t want to surface the client credentials exchange to your customers you can do the following:
- For every tenant that wants access to the API, create a non interactive client in Auth0 and authorize it to access the API you already have configured.
- Provide the client identifier and client secret to the tenant; you can even tell them: “Here’s your API Keys…”
- The tenant would include the API Keys in the request to the API
- The API would extract the API Keys and validate them by trying to use them in a client credentials grant exchange against your Auth0 account.
- If the client grant succeeds than the API Keys are valid and your API can complete the request.
The above, seen from the eyes of the consumer the API, is indistinguishable from the concept of API Keys. From your point of view there would only be the additional consideration that depending on the scale you may be required to implement some caching in order to not always be exchanging the client credentials for a token.
Finally, in relation to the last point about having third-parties building applications that would access your API on behalf of specific users you may want to also have a look at dynamic client registration if you haven’t done so already.
Thanks @jmangelo, it’s great to get this recommendation for our scenario. Regarding the creation of new clients, I’m curious about how the clients work/what they represent:
- Is it possible to reuse our existing clients?
- Will the type of client determine the types of authentications/grants that are possible?
- Is it just not recommended because settings will typically be different for the different types?
I think I kind of get it, but it will be great to just get some more info on this. Part of the reason for asking, is probably an unexplainable wish to keep the client list shorter
Would you recommend that the client sends the API keys in an authentication header using basic auth like "Authorization: Basic " (over HTTPS)?
Restricting grants available depending on the client type is something that I could see happen, but you could still reuse depending on the types of clients you have. However, the main point against reusing clients is that you loose a lot of flexibility. Having a non-interactive client per tenant means you can cut access to that tenant by simply removing the client and it would not affect anyone else. It could also provide better auditing/statistics.
I would go with the Authorization
header because servers know that the header carries sensitive info and it’s unlikely they’ll log that data.