Anton Dedov

OAuth Meets PDP

1. Introduction

OAuth 2.0 and traditional authorization models such as RBAC, ABAC, and ReBAC address different aspects of authorization:

In this article, I would like to explore how these two worlds can be connected without modifying the underlying PDP. In particular, it introduces means to

Basic considerations are:

 

Note: This paper heavily is influenced by the fact that last several years I am working on cloud IAM. So, in many ways it may be biased to cloud authorization scenarios.

 

2. Codify OAuth scopes

On a picture below we’ve got a pieces of two worlds combined:

 

It’s safe to say that a resource API call should be authorized if both claims met:

  1. OAuth client is authorized with a scope required to accomplish the request.
  2. A subject on whose behalf a client is operating is authorized to accomplish the request.

In other words, a request can be found within an intersection between scopes authorized to a client and actual subject’s permissions:

 

So, what we can call a scope? PEP usually calls something like PDP.Check(subject, operation, resource, ctx) so, it looks natural to form an individual scope as a combination of {operation, resource, context} where any element is optional.

Thus, if we take operation as a part of scope, a building part of a scope will be a named set of individual operations (op-scope). In a “classic” cloud IAM this is also known as role (not to be confused with roles in RBAC).

Example: the calendar.editor op-scope could refer to a named set of individual operations like { calendar.event:lists, calendar.event:get, calendar.event:create, … }.

When one choses to use both operation, and resource as a building part, a scope becomes a pair { op-scope, resource-filter }; let’s call it res-scope. Depending on business requirements, it might be useful to use res-scope instead of just op-scope, so client is limited within a resource boundary it cannot escape from.

Examples:

Choosing to extend res-scope with some context parameters makes scopes much more expressive but also system much complex in it’s implementation. For example, a client can be authorized to transfer money to external accounts but only within specific budget limit.

Note: The OAuth Rich Authorization Requests (RAR) specification provides a structured way to express fine-grained authorization requirements. However, it does not prescribe how resource APIs should enforce them. The structured scopes described in this section are merely illustrative, intended to show how OAuth scopes can be expressed using authorization policies supported by a particular PDP.

 

3. Combined OAuth-PDP Architecture

In PEP/PDP architecture, each incoming API-request is intercepted by PEP, which communicates with PDP for authorization decision, e.g. PEP calls PDP.Check() method and either proceed request processing or returns authorization error.

The target architecture aims to express OAuth reality in a “vanilla” PDP without necessity to change it. To achieve this property, the system will have to implement “OAuth-aware” PDP that works as a smart proxy to “vanilla” PDP.

“OAuth-aware” PDP will:

 

4. OAuth Use-cases Mapping to PEP/PDP

Lets discuss following OAuth use-cases in respect to authorization mechanics on PEP/PDP side:

  1. [UC.1] Client makes an API request, with authorization grant persisted by a system.
  2. [UC.2] Enterprise administrator pre-authorize some scopes for all users of his tenant.
  3. [UC.3] Client makes an API request, when authorization grant codified in a token only.

4.1 [UC.1] Persisted Authorization Grant

4.1.1 Persisting Grants

Generally typical OAuth flow can be depicted as series of steps, like:

Depending on authorization flows, details may differ. The important parts here is user’s consent approval and access_token generation.

To express persistent scopes, OAuth authorization endpoint will need to communicate with PAP endpoint to create policies that express OAuth scopes authorized by a specific grant:

Implementation note: Depending on the authorization model behind the PDP, a synthetic subject may either be explicitly created in the authorization system or exist only as part of an authorization relationship. An important property, though, is that it must have a deterministic ID that both the OAuth AS and the “OAuth-aware” PDP can generate from the same input parameters. For example, one could use delegation:{client_id}:{subject_id} as an ID generation scheme.

4.1.2 Token Contents

For this case, for authorization purposes an access token needs only sub and client_id. In this scenario, an access token does not carry scopes. We assume an implicit contract that the absence of scopes claim means that the token represents the default persistent authority granted to the client.

4.1.3 Authorization Flow

To authorize incoming API-request “OAuth-aware” PDP will have to

 

4.2 [UC.2] Persistent administrative grant

In this scenario, an administrator of a tenant grants client some default scopes for all users. For example, organization administrator grants CRM application to access calendar resource API for all users. So users of an organization need not grant those scopes for CRM client on login.

Note: This is illustrative example, as I believe that enterprise OAuth needs it’s own in-depth best practices research.

For this design we assume that:

4.2.1 Persisting Grants

The protocol for administrative grant can vary:

In order to express approved tenant-level grants, OAuth AS will

4.2.2 Token Contents

Same as UC.1: sub, client_id.

Token may also contain explicit tenant ID unless a system can deduce it from subject ID.

For simplicity, we still consider that token does not contain any other scopes definitions.

4.2.3 Authorization Flow

The flow works in a similar way like in UC.1 but taking into account more complex scenarios: client can have approved tenant-wide grants or individual per-user grants.

To authorize incoming API-request “OAuth-aware” PDP will have to

 

4.3 [UC.3] Authorization Using Token-contained Scopes

When a system opts to not persist authorization grant, approved scopes should be placed in a token.

4.3.1 Token Contents

For purposes of OAuth-aware authorization following claims become necessary: sub, client_id, scopes. The scopes claim can be in op-scope or res-scope form, depending on business requirements of a system.

For example, the JWT-alike token can look like:

{
	"sub": {subject_id},
	"client_id": {client_id},
	"scopes": [
		{
			"scope": {op-scope-name-1},
			"resource": {resource-filter-1}
		},
		...
	]
}

4.3.2 Authorization Flow

Some of modern PDPs allows PEP to provide temporary/ephemeral policies that are considered truthful inside a context of a request. OpenFGA Contextual Tuples is an example of feature.

So, if system is integrated with such “vanilla” PDP, “OAuth-aware” will:

Note 1: We cannot use u+c subject instead of token-sub in this case because in the u+c case “vanilla” PDP would not be able tell persisted grants from ephemeral ones that came from token. Thus the token would potentially get more power than intended by it’s creator.

Note 2: This method relies on an assumption that “vanilla” PDP implements the “ephemeral policy” feature in a way of building effective policy set as a union of persisted policies and ephemeral ones passed as a contextual parameter.

When “vanilla” PDP does not support ephemeral policies, “OAuth-aware” PDP will probably have to emulate it’s behavior. This approach would make “OAuth-aware” PDP to incorporate knowledge about resource/policy structure and at least partially duplicate some logic “vanilla” PDP. So this is rather architectural trade-off.

4.4 Put Puzzle Together

Finally, we can unify the approach from all three use-cases into one picture. Actually, there will be two pictures depending on fact if token contains specific scopes or not:

   
Token does not contain scopes
Works according to 4.2.3
Token contains scopes
Works according to 4.3.2

4.5 More PDP Features in Charge

“OAuth-aware” PDP should always pass client_id from an authenticated token as a part of authoritative context attribute to “vanilla” PDP during subject permissions validation, e.g.:

	PDP.Check(sub, operation, resource, ctx.client_id = {token.client_id})

This may enable useful features on “vanilla” PDP side (if it has support):

 

5. Further Development

This article does not cover client credentials, token exchange, multi-party authorization, and other useful delegation scenarios. I see good research perspectives in that respect.

The closest intuition I’d like to pay attention in near future is mixing restrictive and permissive structures in tokens. IMHO to be fully PDP-friendly OAuth tokens could be like:

{
	actor: {active-actor},
	scopes: [
		{
			scope: {permissions-scope},
			resource: {resource-filter}
		},
		...
	],
	delegations: [
		{
			delegator_subject: {sub-1}
			scope: {permission-scope},
			resource: {resource-filter}
		},
		...
	],
	...
}

With such design, one could construct tokens that are both scope/resource limited and also include active delegations from a number of subjects enabling transactions over complex resources administrated by different parties. And potentially allow resource usage scenarios that span more than one administrative/trust domains.

6. Conclusion

In the article we propose an architecture pattern for OAuth-aware authorization in a traditional PEP/PDP framework. The pattern has several attractive properties: