How to login in a SPA and obtain a token to call into an API?

I have the following setup:

  • A React app which needs user authentication (configured as a SPA client in Auth0).
  • An HTTP API using Node/Express (configured as an API in Auth0).

When the user logs in, the application needs to be able to perform authenticated API calls. The API expects tokens signed using RS256.

The application is using Auth0.js to perform the login:

this.auth0 = new auth0.WebAuth({
    clientID: 'xxx',
    domain: 'xxx.auth0.com',
    responseType: 'token',
    // audience: 'https://myapi.example.com/',
    redirectUri: 'xxx'
});

When not using the audience parameter the login works fine and I’m getting an ID Token. According to information found online, the id_token is supposed to work as an access_token if the SPA is a first party client. However, I’m not able to find any information about how to set it as a first party client.

On the other hand, when using audience I’m just getting an access_token which causes login to not complete successfully.

How do I login a user (in a SPA) and at the same time get an access_token in order to connect with my back-end API? Do I need to explicitly authorize that user within the configured API?

The client application first party flag is currently not shown on the Dashboard, however, you can query it through the Management API Get a client endpoint, more specifically, the is_first_party response field.

If you haven’t taken explicit steps to make the client application a non-first party client then by default it will be true.

Assuming that you treat your client application (SPA) and resource server (API) as two independent entities and you additionally intend to authenticate calls to your API through the use of bearer tokens, then I would recommend that you maintain the mentioned setup in Auth0:

  • a client application record to represent your SPA;
  • an API record to represent your API.

Your client application then performs an authentication request with an audience parameter included and targeting your configured API:

this.auth0 = new auth0.WebAuth({
    clientID: 'xxx', domain: 'xxx.auth0.com', redirectUri: 'xxx',
    responseType: 'token',
    audience: 'https://myapi.example.com'
});

You use the returned access_token to make further calls to the API.

In addition, it’s highly likely that your SPA application will want to have some idea of who is currently using the application so that it can customize the UI (aka You’re logged in as John Doe). In order to accomplish this, you update the requested responseType to include an id_token so that you also get an ID Token containing information about the current authenticated user. Given the ID Token is an OIDC artefact you’ll also include a scope of openid in order to comply with that specification.

The end result:

this.auth0 = new auth0.WebAuth({
    clientID: 'xxx', domain: 'xxx.auth0.com', redirectUri: 'xxx',
    responseType: 'id_token token',
    audience: 'https://myapi.example.com',
    scope: 'openid'
});

You can include further scopes to get more user information, for example, scope: 'openid email' or scope: openid profile' or even scopes associated with your own API.

Have in mind that when using the audience parameter in the request or when explicitly enabling OIDC conformance for a given client, the set of claims returned automatically within the ID Token are restricted to the ones defined in the applicable specifications.

However, you can control the the inclusion of additional claims using rules. For example, the following snippet within a rule:

if(context.accessToken) {
  context.accessToken"https://my.example.com/ref"] = user.app_metadata.reference;
}

would add an additional claim to the access token (you would use context.idToken if you’re interested in adding to the ID Token).

Also note that the claim type will need to be namespaced (https://yournamespace/claim) so there’s no risk it will conflict with claims defined within applicable specifications.

2 Likes