Unexpected scopes added into user token in ROPG flow

Problem statement

I have noticed that all the scopes in an audience are added to the user’s token if there is no space at the end of the scope string. Is this a bug? I am not using RBAC.

I am using ROPG to get a JWT token from a password-based exchange. I understand that password-based exchange returns all scope if it is not defined, but I am trying to get a reduced set of scopes. It also returns some customized scopes which are not related to OpenID or any other scope.

Cause

This behavior is by design.

In our Call Your API Using Resource Owner Password Flow documentation, it mentions the following:

  1. If you request the openid scope you will get all OIDC scopes.
  2. If you include no API scopes in the request, all API scopes will be included in the Access Token.

Given scope is a space-delimited list of values, our logic is likely doing a split by space character, but possibly not removing empty entries (caused by adding a space at the end of the list). This can then imply that when you pass openid (no space at the end) our logic sees a list with a single scope and that single scope is an OIDC scope so it would imply the request has not included any API scopes and as such point-2 above should kick-in and cause all API scopes to be included.

However, when you request openid (space at the end) our logic likely sees a list containing two scopes; one is the oidc scope, and the other is an empty string. Given an empty string does not match any of the standard OIDC scopes our logic may assume that at least one API scope was provided so point 2. above does not kick in which then possibly leads to a different behavior.

Getting a reduced set of scopes is already possible if the request includes at least one API scope; so if API defines scopes do:x and do:y you can include only do:x in the request and only that API scope will be given. If the API in question accepts a token without any API scopes but with the API audience as valid and as capable of performing some basic operation, the recommendation would be to model the most basic access level to the API as a scope on itself.

In other words, the API should now define basic_access, do:x, and do:y scopes. When you want an access token that can do a basic operation but cannot perform any of the do:* operations you would perform a ROPG grant that passes the basic_access.

Solution

In conclusion, there may indeed be a degree of unexpected behavior in the current logic around space handling, However, even if that is addressed, the fix may end up being irrelevant and possibly even counter-productive to what you might expect.

Ultimately, we recommend modeling the API as a scope (basic_access) and then requesting access using just that scope.