Is it possible to restrict the scopes available to a SPA

I am having a API created in the Auth0 dashboard which has a couple scopes, say read:one and write:on. I also have a SPA application registered. I am going to use the client id of this SPA for my actual SPA. Now I know that when my app requests an access token from Auth0, I can pass the scope parameter to restrict the scopes. But, the application can request any scope defined in the API registration. Is there a way to restrict the available scopes to a SPA so that the returned token doesn’t contain the restricted scopes even if the application asks for it?

There’s built-in support through (https://auth0.com/docs/authorization/how-to-use-auth0s-core-authorization-feature-set) to restrict the scopes returned based on the user that is performing the authentication.

There’s also support for restricting scopes based on client application, but only in client credentials flows where it’s the client itself that authenticates (no end-user).

Can you share the use case for needing to restrict scopes not just per user, but also based on the application through which they are authenticating? From a technical perspective restricting the scopes per application in end-user based flows may be possible through rules, but that can be both complex as well as not really meaningful in some scenarios.

2 Likes

Sure. We have a microservice backend with each service exposing their own APIs. We will have more than 1 distinct product and there are some microservice that might be accessed by more than 1 product.

For clarity’s sake, I will assume that each product has a single frontend SPA. Now this SPA needs to access and auth to multiple backend APIs but not all backend APIs. There might be an API to be exclusively used by the second product. Since, I can’t auth multiple audiences at the same time, so I can’t have each of my backend service be a separate API entry in Auth0.

So, I decided that I will create a single logical API, as mentioned in Represent Multiple APIs Using a Single Logical API. So, since I have 2 products, I thought that I can create 2 scopes, access:product1 and access:product2. Essentially, what I want the token generated by the SPA of product1 to not be valid for a product2 exclusive backend.

So, I thought that if my product1 SPA could restrict which scopes it can accept, like client-credential does, I could ensure that a user cannot reuse a token that is generated for this SPA to call an API for product2. But, implicit/auth-code-pkce flows use the scopes sent in the authorize request and that is all that is required.

Now, I am not a security expert so I might be making a problem out of a non issue. If it’s so, please let me know so.

Also, let me know if any clarification is needed.

If all your applications are SPA’s, from the point of view of OAuth/OIDC, all of them will be public client application. In other words, they will be unable to act as confidential clients because they won’t be able to keep a client secret for the the purposes of client authentication.

The above will imply that the authorization server will only receive the client identifier and can/will indeed act based on that client identifier. For example, it will only return a response to allowed callbacks for that specific client, however, if you would attempt to control scopes based only on that identifier a sufficiently technical user would just use the client identifier of the client that allows that scope to get a token. In other words, things may get complex fast because although you could now also apply a rule that prevents user A from performing a login in the scope of application B this approach may not scale well.

It seems easier for this case to just associate permissions/scopes to the user; in other words, if the user has access to both products if he tries to get a token for product2 through the front-end SPA of product1 it’s technically incorrect, but not an a security issue as he also has access to product2.

In other words, preventing at the user level that user A can’t get a scope for a product that they should not be accessing seems simpler and likely more correct.