"OR" required_scope with oauth2_introspection

Hi everyone,

I’m currently building an API that use Hydra for the oauth2 mechanism and Oathkeeper for the introspection and reverse proxy.

Our API scopes are inspired by the Google APIs scopes:
Some example for our datamodel API:

  • org.example.api:datamodel
  • org.example.api:datamodel.models
  • org.example.api:datamodel.models.readonly
  • org.example:api.datamodel.links

They are hierarchic, which means if you give the scope org.example.api:datamodel.models you will have access to org.example.api:datamodel.models.readonly but no org.example.api:datamodel.links.

The way I handle that for the moment is by configuring Hydra and Oathkeeper with the hierarchic scope strategy. The problem is that it has been deprecated (I guess it’s because it’s too permissive).
Also the second problem is that I can’t control what scope the users are requesting while calling the authorization endpoint (They could ask for org.example:api.datamodel.links.doesnotexist)

Another way I could handle my scopes would be to configure Hydra and Oathkeeper with the exact scope strategy and to set in the required_scope field in the rules a list of scopes in which the user should at least possess one.
Example with a models readonly endpoint (the user should have at least one of these scopes to be able to call this endpoint):

  • org.example.api:datamodel
  • org.example.api:datamodel.models
  • org.example.api:datamodel.models.readonly

The problem with this method is that the field required_scope in the Oathkeeper rule works with an AND logic and this method require an OR logic.

Do you have any thought on how I could handle my scopes or make Oathkeeper working with an OR logic ?

Thanks in advance for any help

Hm, isn’t „org.example.api:datamodel.models.readonly“ less permissive than „org.example.api:datamodel.models“? Would an OR not make false assumptions here?

In general however I think there should/could be some logic for scopes in oathkeeper. But bear in mind that OAuth2 scopes are not permissions in the traditional sense but instead things a user allowed some oauth2 client to do in their name.

For example, I could tell some Facebook app „yeah you can act as an admin on my behalf“ but that doesn’t mean that I am a dacebook admin!

The idea behind our logic is:

If an application ask for org.example.api:datamodel.models.readonly scope it should only allow the application to read datamodel on behalf of the user.
But if If an application ask for org.example.api:datamodel.models scope it should also allow the application to create, update or delete datamodels on behalf of the user.

That’s why I wanted to use an OR scope stratey,
For the GET endpoints I would have set the following scopes:

  • org.example.api:datamodel
  • org.example.api:datamodel.models
  • org.example.api:datamodel.models.readonly

But for the POST, PUT and DELETE endoint, only this set of scopes:

  • org.example.api:datamodel
  • org.example.api:datamodel.models

Right, that would be with the exact matching strategy, right?

It’s what I would like to do, however if the user has only the scope org.example.api:datamodel.models and try to request a GET endpoint, his request will fail because the required_scope option in the rules is following an AND strategy.

I see, I think it’s generally a bit difficult to model this with JSON unless we have nested operators which are just really ugly to code, e.g.

- op: and
  values:
     - a
     - a
     - op: or
       values:
       - a
       - b 

and so on.

Another alternative is to have some parsing such as foo && bar && (baz || zab) but this too is kind of tricky to implement and write.

I’m not sure if we want to go full-force with AND and ORs in the code. In my opinion, you’re mixing sort of permissions with hierarchy with high resolution with plain strings. Typically, you would not see such extensive permissions as scopes. In fact, most systems have quite simple scopes such as:

  • repository:write (github)
  • repository:read (github)
  • repository:all (github)

or some others. I would recommend checking the big OAuth2 providers such as Google, GitHub, and maybe some others to see how they solve OAuth2 Scopes.

What you’re trying to achieve sounds to me like real access control, which is probably better left to something like Open Policy Agent, Keto, RBAC, ACL, …

Hi thanks for the answer and sory for the delay

I understand that the implementation of an AND or OR logic would be hard to implement.

As stated in my first message, our scopes are inspired by those of the Google APIs, (except that we are using the reverse form of the api host instead of an URL). I’m not trying to achieve any access control with the scopes but would like to protect our user by instructing them of what functionality of the API they are giving to a third party application.

I’m not sure how I could implement the github scope strategy you are proposing as I will encounter the same problem:

Suppose I have an API with the following endpoint:
GET /repository: require the scope repository:all or repository:read
POST /repository: require the scope repository:all or repositort:write

It seems logic to me to configure Hydra and Oathkeeper to use an exact scope strategy. However if I’m doing this, an user will require the scope repository:all AND repository:read to access the get endpoint.

Sorry if I’ve not understood something but how would you implement the github scope strategy ?

Depends on your definition of all (which I interpret as all privileges) but yeah I get your point.

What would you propose in Oathkeeper to resolve this issue?