I have an Auth0 tenant which has a Single Page App Application defined. I also have the Auth0 Management API defined.
Currently, I have a single SPA deployed that has the following properties defined:
Authority: The value of the Domain setting on the SPA Application
Audience: The value of the Identifier on the Auth0 Managment API
ClientId: The value of the Client ID on the SPA Application
I have several APIs that are all configured with the same properties as above.
This all works as expected. The SPA handles the handshake with Auth0. Passing the Auth token received from Auth0 as a Bearer token to the APIs is making sure that the tokens are valid by getting the relevant keys from Auth0.
Now what I want to do is allow APIs to call each other in a Maching-to-Machine scenario. As this is not going to be on behalf of the user. I don’t want to allow any endpoint to be called so I wanted to use scopes.
I am really unclear on how best to approach this. My instinct is that each API should be created as an API in Auth0 with the relevant permissions defined, and then each API that needs to call another API should also be created as an Application in Auth0 with the correct permission mapping. However, they all end up with different Identifiers and thus Audiences. So this all seems to fall apart.
The best way to model this is to create each API in Auth0 with its own permissions and create a separate M2M app per API that needs to call another API. Then grant each M2M app the permissions to different APIs that it needs to access.
In this approach, it’s true that they all end up with different identifiers AKA audiences. And that’s okay because each API can call another API through the client credentials flow.
If I do this then the issue I have is that my SPA needs to call all the APIs with the Auth token of the user. With my current set up that means that the audience in the token will be the Identifier of the Auth0 Management API and so it won’t be authorised to call any of the APIs as the audience will not match.
How can I support both M2M from API to API, and Authorisation Code Flow with PKCE for end users via the SPA?
In this scenario, you would continue to use your SPA to allow your users to log in with the authorization code flowing with PKCE. During login, it’s okay passing in the Management API as the audience. Once the user logs in, they will be issued an access token that has access to the Management API.
Then, within your SPA, when your APIs need to call other APIs, you can use the client credentials flow for those requests.
Ultimately, you will have to use both flows for this to work.
Thanks again @rueben.tiow. To achieve what you are saying do I need to configure components with multiple audiences?
Let me expand.
SPA
This needs to authencate users with authorization code flowing with PKCE flow. The auth token that is issued for the user must be able to be used with APIs 1, 2, and 3.
API 1
This has no external dependencies on any other APIs.
API 2
This needs to be able to call API 1.
API 3
This needs to be able to call API 1.
Questions
When I configure the SPA do I need to add all the audiences for the the Management API, and each of the APIs that it will need to call on behalf of the user?
When configuring each API do I just need to add the audiences for both the Management API and the API itself?
For M2M when I request the token via Client Credentials flow. I only need to request the audience of the API I want to call?
Unfortunately, it’s not possible to configure multiple audiences in your login request.
(Reference: How to Specify Multiple Audiences)
However, if you call each audience individually, you can get access tokens for those APIs independently.
Not necessarily, this depends on whether that M2M app needs access to the Management API and the API itself.
If so, you can configure the M2M app to have authorized access to those APIs with its permissions.
Let me expand on your example:
SPA
You could use your SPA to authenticate users using the authorization code flow with PKCE and specifying access to API 1. If the user needs access to API 2 or API 3, one way is to silently authenticate them against those APIs.
API 1
This is fine because there are no external dependencies on any other APIs.
API 2
For API 2 to call API 1, it could initiate a client credentials flow. There would be an M2M app registered that API 2 can use to call API 1.
API 3
It’s the same situation here. To call API 1, API 3 would initiate a client credentials flow. This can be the same M2M app registered earlier that API 3 can use to call API 1.
Yes, this is correct. If your M2M app has authorized access to an API with its permissions (scopes), you can request an access token via the Client Credentials flow, specifying the audience of the API you want to call.
Thanks again @rueben.tiow. I think I understand now. Here are hopefully my final questions:
I understand that I can consolidate all of my logical APIs into a single API in Auth0. Then by using permissions I can segregate the scopes needed for different actions across all of the APIs. What do I need the Management API for in a SPA + n APIs architecture?
The management API by default has many permissions defined: e.g. read:client_grants, read:users, etc.. Are these required for my SPA to authenitcate an end user?
When you say I can silently authenticate the other APIs. What do you mean?
To clarify I am saying can I create a single API in Auth0 and configure the audience in all the APIs and the SPA. The just use the same Auth token for all requests?
Well, this depends on whether you need to use the Management API to change a resource or configuration on your tenant. Since you mentioned it in your initial post, it sounds like you might have a use for it. If not, you can use a custom API instead.
Yes, that’s correct. However, your SPA does not need those permissions to authenticate an end user. You only need them if you intend to make specific calls using the Management API.
Note that there is a small list of permissions you can request as scopes in the context of an SPA, which is limited to certain endpoints. You can find them here.
Silent authentication is a way to re-authenticate a user without displaying any user interaction. So initially, when you authenticate the user, it prompts the user for their credentials. In the future, when you want to authenticate to another API, you could try silently authenticating, which does not prompt the user again for their credentials and re-authenticates them against the second audience.