What grant/endpoint to use for authentication in a React SPA that accesses external API?

I have a SPA in React that makes calls to an external API like: GET https://myapi.com/api/items/1 or GET https://myapi.com/api/items/.

In myapi.com server, the routes are secured with OAuth2 using express-jwt and auth0-api-jwt-rsa validation, so only calls with an appropriate authorization header Authorization: 'Bearer ' + token respond with success.

If I was going to consume these calls from a server side application I could obtain the token from POST https://[account].auth0.com/oauth/token passing client_id, client_secret, grant_type and audience. But since the application is client-side I think there’s a best approach, avoiding to expose client_secret and so on.

I tried the implicit grant approach but I’m dealing with the callback URI and other confusing stuff.

The main idea is to allow the application, say https//myapp.com/list to consume the API like GET https://myapi.com/api/items (without users, without passwords).

You reached the right conclusions; the use of the token endpoint either for client credentials grants or resource owner password grant (ROPC) is not recommended for a SPA. The client credentials grant is outright not possible because the client application (SPA) is unable to maintain a client secret without disclosing it to anyone interested in obtaining it.

This means that if you want a SPA to access an API without the notion of a user, then that API needs to be public. The approach available for a SPA would be to include the notion of user credentials, because with users the credentials would be stored by the user and not the SPA. You can make this as simple as a common set of user credentials used by everyone that needs access, but you would have to have users involved so that the credentials can be stored by the users themselves and not the SPA.

For a user based flow although ROPC is possible, is not recommended given the availability of other options. The recommended approach would be indeed to use the implicit grant. In general, with the implicit grant you could implement something like the following:

  • The user accesses your SPA application.
  • The SPA application redirects the user to Auth0 so that they can authenticate and provide consent for your application to access the API in question.
    • I mention consent, but this may be implicit consent and such transparent to the end-user; it’s dependent on your exact configuration.
  • The user completes the authentication and authorization procedure.
  • The Auth0 identity provider redirects back the user to your client application with the issued tokens.
    • The issued tokens will likely contain an ID token and an access token, but this depends on you performed your request.
  • Your client application, as part of the response to triggered callback URL, processes the tokens.
  • You use the ID token to know who the user is (get some information about them) and the access token to call your API.

The above assumes that you correctly configure your SPA to make an initial request for user authentication and API authorization; this generally boils down to including the openid scope to signal that you’re making an OpenID Connect request, requesting a response type that includes both an id_token and an access token (token) and finally including an audience parameter to indicate which API is the target of your API authorization request.

You can achieve this by making use of Auth0.js v8 and not having to deal with making the raw requests to the underlying authorization endpoint. In particular, check the webAuth.authorize() method available in this library.

If you have a specific issue with the above process then please create a new question that focuses on that issue and contains all the information you think may be relevant to it.

Thank you for the clear answer @jmangelo.

Yes, I think that for my needs I have to use a public API not involving users and passwords then.