No way to limit allowed scopes for a consumer using client credentialss

Created on 20 December 2024, 4 months ago

Problem/Motivation

In Simple OAuth 5.x any (additional, i.e. not provided by default by the client/consumer) scopes requested as part of token creation were validated against the list of of roles attached to the user. This was removed in 6.x so that the token contains any requested scopes as long as they (exist and) are enabled for the respective grant type. Instead, access for a particular permission is now checked against the user associated with the token in addition to the scopes attached to the token, at least for authorization codes and refresh tokens.

For client credentials, however, this additional check against the user associated with the token is not performed (as it does not really make sense there). This, however, means that any client that can create a valid client credential token (by knowing a consumer ID and secret) can request any existing scope that has been enabled for client credentials and will be granted the respective permissions implied by that scope.

That, as far as I can tell, effectively makes client credentials unusable with this module as soon as you want to achieve different access levels. I.e. if you want to have some consumers/clients that are less privileged than others but you want both types to able to authenticate via client credentials, you are out of luck.

I had thought that the "Scopes" field could be used to achieve this, and on its face it did seem to, because by default the tokens I created with different clients/consumers did have different scopes. But after reading some of the related issues and, admittedly the field description: "Here you can select scopes that would be the default scopes when authorizing." (emphasis mine) I realized that this is only the default and verified that, in fact, all of my clients/consumers have access to all scopes.

Steps to reproduce

Proposed resolution

?

Remaining tasks

User interface changes

API changes

Data model changes

šŸ› Bug report
Status

Active

Version

6.0

Component

Code

Created by

šŸ‡©šŸ‡ŖGermany tstoeckler Essen, Germany

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Merge Requests

Comments & Activities

  • Issue created by @tstoeckler
  • šŸ‡³šŸ‡±Netherlands bojan_dev

    This is a valid point, we should definitely reintroduce this feature. The question is how? We could add an extra responsibility on the default scopes, so it limits the scopes per consumer or we can introduce an additional field where we can specify allowed scopes. Iā€™m open for suggestions.

  • šŸ‡³šŸ‡±Netherlands bojan_dev

    I went ahead and made the default scopes limit the allowed scopes per consumer. Can somebody please review?

  • šŸ‡©šŸ‡ŖGermany tstoeckler Essen, Germany

    Thank you so much for working on this! From looking at the code that is exactly what I had in mind, just wasn't sure you would be open to that change. That's really great šŸ‘ļø

    I had meant to test this last week, but that didn't work out and I'm off this week, but will try to prioritize checking this out next week.

  • šŸ‡©šŸ‡ŖGermany tstoeckler Essen, Germany

    Tried out the code now and it works exactly as expected. The tokens now automatically get the scopes selected for the client/consumer and any additional scopes are rejected.

    I only have one question: When I was testing I initially set up my client to have no scopes at all. In that case this validation logic is not applied because it is within the

        if (!$client_drupal_entity->get('scopes')->isEmpty()) {
    

    block. Even though it's not a very practical scenario, I would have expected the created tokens to have no scopes in that case instead of any requested scopes.

    Will set to needs work for that.

    But thanks again for working on this, really much appreciated.

    One other aside, as I don't know where else to mention this: I built a tiny module that allows creating client credential tokens via the Drupal UI, to save administrators having to use Postman or whatever to do that. Since it's fairly generic I am planning to contribute it. I am presuming, though, since it's somewhat of a niche use-case that you wouldn't want to have that in Simple OAuth proper so I am planning on a separate little module. But wanted to check with you first, just in case that's something you'd be interested in having directly as part of the main module.

  • šŸ‡³šŸ‡±Netherlands bojan_dev

    If there are no scopes requested and no scopes are set on the consumer with the client credentials, in 5.2 it will fallback on the default user (set on the consumer), with 6.0 you won't have any access. We definitely need to address this in 6.0, I think we should grant all scopes that support client credentials if no scopes are set on the request and consumer.

    Regarding the tiny module, it would be interesting to have some testing/debug submodule available that does this. I would be open to add this to the module.

  • šŸ‡©šŸ‡ŖGermany tstoeckler Essen, Germany

    That's fair enough. I think it's a bit unintuitive that if you do have a consumer with client credentials and no scopes initially and select a single scope it actually reduces the amount of possible scopes for that consumer. But, yes, that scenario will only really happen during initial setup or testing, it's not really a sensible "production" configuration to have a client credential consumer with no scopes. Maybe we could amend the description, though, to make people aware of this nuance? In any case, that was the only reservation I had so marking RTBC.

    That's great regarding the module, I will open an issue for that, hopefully will get around to that this week, let's see.

  • šŸ‡³šŸ‡±Netherlands bojan_dev

    To be in line with the OAuth2 spec: https://datatracker.ietf.org/doc/html/rfc6749#section-3.3
    I have made the token endpoint require the token scope parameter when there is no default scopes available on the client/consumer when dealing with the client_credentials.

    Could you please review my last commit?

  • Status changed to RTBC about 2 months ago
  • šŸ‡©šŸ‡ŖGermany tstoeckler Essen, Germany

    Hey there, tested the last commit now, sorry for taking a bit.

    I tested three scenarios:

    1. No default scope in consumer and no scope in request -> { "error": "invalid_request", "error_description": "The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed.", "hint": "Check the `scope` parameter" }
    2. No default scope in consumer and scope in request -> token with requested scope granted (again, this is the case I find suboptimal, but it's not a realistic production use-case anyway)
    3. Default scope in consumer and no scope in request -> token with default scope granted

    So looks perfect from my point of view

  • šŸ‡³šŸ‡±Netherlands bojan_dev

    Thanks for reviewing/testing @tstoeckler!

  • Automatically closed - issue fixed for 2 weeks with no activity.

Production build 0.71.5 2024