Fetching an M2M Token Returns All Granted Scopes/Permissions Instead of Requested Scopes

Problem statement

After configuring several APIs to be granted access, with limited permissions, to a handful of machine-to-machine (M2M) applications the following observations have been made:

  • If a token is requested by an M2M app, and no scopes are specified in the request, then the access token returned has all granted scopes for the given M2M app as expected
  • If a token is requested by an M2M and a subset of scopes are specified at the time of request, then the access token will still include all the scopes enabled for the M2M app.

The second bullet point seems like unexpected behavior, is it possible to retrieve an Access Token with a subset of approved scopes for a given M2M app?

Symptoms

  • Make a call to a custom API using the Client Credentials flow.
  • Inspect the returned access token and confirm all scopes are returned, even if a subset of scopes were requested.

Steps to reproduce

By way of example:

curl -sS --request POST \
--url "[https://auth.dev.example.com/oauth/token"](https://auth.dev.example.com/oauth/token)" \
--header 'content-type: application/x-www-form-urlencoded' \
--data grant_type=client_credentials \
--data client_id="abc123def578" \
--data client_secret="**REDACTED**" \
--data scope="read:claims" \
--data audience="api2"

In this example, there could be an expectation to get back only the “read:claims” scope that has been specified. But in fact, all of the API scopes will be returned.

Cause

During a client credential flow, the scopes returned will always be the full set of authorized scopes for the M2M app. This holds true, even if a subset of the available scopes were requested.

Solution

Use a Client Credentials Hook to manipulate the scopes that are returned. This can be done by passing in additional scopes to the access_token.scope.push('extra') method.

Unfortunately, this capability is not yet possible in Actions ( correct as of February 2024 ).