Search code examples
authenticationsecuritysingle-page-applicationopenid

Is it appropriate for an application (SPA) to pass an "extra" access token to a backend service (so that service can call other services)?


I have a web application (SPA), which we'll call A. This application calls an API service (that I control), which we'll call B. Service B uses OAuth authentication, and trusts an issuer I.

In my scenario here, there is another API service C (which also uses OAuth authentication and trusts issuer I) that I do not control. In some circumstances I need service B to call service C in response to a user's request from A to B. I can see two (obvious) options here:

  1. The user, via application A, authenticates using the "authorization code flow with PKCE", receiving an identity token. This identity token can be exchanged by A for an access token with the necessary scopes for service B. Application A uses the access token to authenticate to B, and passes the identity token along with the request, and B uses the identity token to request an access token with the necessary scopes for service C. B uses this (new, second) access token to make one or more requests to service C. This seems bad because one is never supposed to pass an identity token to any service.
  2. The user, via application A, authenticates using the "authorization code flow with PKCE", receiving an identity token. This identity token can be exchanged by A for an access token with the necessary scopes for service B. Application A then uses the identity token to request a SECOND access token with the necessary scopes for service C. A uses the first access token to authenticate to service B, and passes the SECOND access token along with the request. Service B uses this SECOND access token to make one or more requests to service C on behalf of the user. This seems less bad, but still not great.

As far as I can tell, it is not possible to request and access token that applies to both B and C, because they are separate resources (not simply different scopes in the same resource). It seems to me that this would be a very common scenario; if my API service needed to make requests to a blob store (i.e. Azure blob storage or S3) on a user's behalf, or requests to a database server?

Is there a third scenario that I do not know of, or is one of these the correct approach?


Solution

  • The key search phrase for this kind of situation is "downstream API". It is handled by OAuth's "on-behalf-of" flow. It is implemented by the IConfidentialClientApplication interface in ASP.NET, and documentation can be found here: https://learn.microsoft.com/en-us/entra/identity-platform/scenario-web-api-call-api-app-configuration?tabs=aspnetcore