OAuth 2.0 with complex or fine-grained scopes - oauth-2.0

I am currently working on an OAuth2 implementation for all the clients (web and mobile). So far nothing fancy about it, but we want to have more complexity in the scope, so that we can grant partial access to certain objects down to the granularity of a single property.
Example: Client gets access for a resource, let's say a user object with all its common properties. The client has full read access, but is only allowed to edit certain properties, e.g. password and username, but not location and/or birthday.
So far my thoughts are, that this granularity is defined at the Authorization Server and just interpreted by the Resource Server.
Based on the RFC the scope is a string based comma separated value, so a plain list (https://www.rfc-editor.org/rfc/rfc6749#page-23)
The value of the scope parameter is expressed as a list of space-
delimited, case-sensitive strings. The strings are defined by the
authorization server. If the value contains multiple space-delimited
strings, their order does not matter, and each string adds an
additional access range to the requested scope.
scope = scope-token *( SP scope-token )
scope-token = 1*( %x21 / %x23-5B / %x5D-7E )
So my first assumption providing json as the scope may not work, so I thought about introducing namespaces which might get to complex, e.g. (scope: user-write-full-read-list of properties or something similar).
Is there any best practice, am I missing something in the RFC or am I abusing OAuth completely?

You may want to consider the UMA protocol. The UMA RPT token is presented by the client to the Resource Server. The RPT token is issued by the Authorization Server (AS) with certain scopes. On the AS, scopes map to policies, such as who can get to what API's using which clients, network, required crypto, time of day, etc. These policies may be expressed in code or a more structured policy syntax like XACML, such as David suggested above.
If you want to learn more about UMA, I would start with this diagram:
In this case, there are two OAuth2 clients: the Resource Server (the thing with the APIs) and the Requesting Party (either a mobile application or web site).
The PAT and the AAT are normally OpenID Connect client tokens. The UMA Core spec says "OAuth2", but the only profile of OAuth2 for crypto client registration is OpenID Connect, so its implicit.
The Resource Owner is the one who makes the policies. These policies can be algorithmic or may require action by the Resource Owner. For more information about OpenID Connect, see
OpenID Connect Website
For more information about UMA see:
UMA Website
If you are looking for a free open source OAuth2 authorization server, you should take a look at the Gluu Server, which is an OpenID Connect Provider and an UMA Authorization Server for FOSS Access Management

You're abusing OAuth here. Scopes are meant to define basic permissions but not fine grained access rights let alone authorization policies.
You should use XACML for that. In XACML, you also have the notion of an authorization server (the policy decision point or pdp). It's configured using policies. It sits in the infrastructure. It is queried at runtime by the policy enforcement point which protects your api/app.
Check out developers.axiomatics.com for details (disclaimer: I work for Axiomatics)

Related

OAuth2: Client Credentials flow

Problem: I am currently working on making a REST Api available to clients (the client in this case is not the normal end user who orders the articles, but the client's Web Api that communicates with my system). In order to order different products in my system, each customer may have several accounts for each country separately. Authentication is done by authenticating the client's WebApi application to my system (machine to machine). So it looks like this should be done using OAuth2 Client Credentials Flow based on the article https://learn.microsoft.com/en-us/azure/active-directory/develop/authentication-flows-app-scenarios#scenarios- and-supported-authentication-flows, but I have doubts about the issue of client accounts for each country separately.
Question: This should be solved by creating a ClientId and ClientSecret for each client account per country separately or, however, one client account should be created, while the country should be sent by the client in each request to the Api or before adding the country as a scope or claim to access token.
Additionally, I am not sure if Client Credentials Flow is a good choice in this situation, so I would be very grateful for any suggestions.
CLIENTS
Ideally each client company should have a single client credential for getting access tokens. In sone cases, such as when there are different legal subdivisions, this can be extended. By default use a single value, but you need to understand your clients.
A client credentials flow between companies can involve stronger credentials if needed, such as JWT client assertions or Mutual TLS - as in this advanced tutorial.
CLAIMS
In your system you should map domain specific data needed for authorization against each client ID. This might include country specific access to products or whatever makes sense for your scenario.
This data can then be either included in access tokens at the time of issuance, or looked up when an access token is first received, then cached for subsequent requests with the same token. Step 3 of my Authorization Blog Post explains a couple of design patterns here.
API REQUESTS
How the client gets data in API requests is interesting:
Is data for all countries owned by the caller? If so let them select the data they want via a country parameter during API requests.
If the API client shoild never be able to see data for a country, that suggests that in at least some cases you need different clients per country.
SUMMARY
Define clients in terms of what makes sense for those companies. Avoid an explosion of clients in order to manage access rights for the same data owner. Exact solutions depend on your domain specific requirements. OAuth is a framework that is meant to be adapted.
If your entire existing data-model silos 'countries' by a concept of an account, then a set of credentials per account might be the easiest.
But it sounds to me that your data-model doesn't fully capture your actual business well. It sounds to me like you have a concept of a 'customer/client' that has access to one of more 'accounts', each representing a country.
So a more correct way to model this might be to structure your API so that a single API client can access all of the related accounts, and your API should perhaps be structured so that the idea of an accountId is somehow passed (usually in the URL for REST apis). For example, each API endpoint can be prefixed with /account/123.
To me this is more of a data-modelling and API architecture question than anything OAuth2-specific.

Securing URL with user owned resources in OAuth2

I'm aware of how OAuth2 and OIDC can use custom scopes and token introspection to secure an URL like this:
/users/me/documents
I can give this URL the documents:view scope and when receiving the token from the authenticated user, I can ask the authorization server if this user has the correct permissions. Then I can use the preferred_username claim or similar to see who /me actually is.
But what if I have a resource which is accessible by multiple users? Let's say a user has documents but they can be viewed by his direct manager. To retrieve the employee's documents as a manager, I'd need to have an url like this:
/users/${userId}/documents
How could I enforce it in a way that only the resource owner and direct manager can view this resource? I don't want everyone to access everyone's documents by knowing the userId. I could grant access as a whole to all users with the manager role, but that's not specific enough.
I'm aware there's the UMA extension where users can grant access to resources on his behalf to other users, but it's not the user who grants permission. It's the system who states in this case that managers can access their employees documents.
Would it make sense to write a custom policy which extracts the ${userId} and performs the check? Or should this not be done by the authorization server at all and be done by the resource server instead? Perhaps a different approach to reach the same goal?
Finer grained authorization like this is done with claims rather than scopes. There may be business rules around which docs a user can see, eg:
A user can access their own docs
An admin has view access to all docs
A manager can view docs for people they manage
In an access token this might be represented by these claims:
userId
role
Claims are often domain specific like this and the preferred option is to add them to tokens during token issuance. At Curity we have some good resources on this topic:
Claims Best Practices
CLAIMS AND AUTHORIZATION
The Authorization Server issues access tokens and then APIs (resource servers) verify the access token and use the token data to apply authorization rules (which are often domain specific) on every single request.
Claims are often used when dynamic behaviour is needed - they are runtime values that derive from the user identity, whereas scopes are fixed design time values. In your example an API might also need to vary SQL to retrieve documents based on the user identity.
There are more complex variations on this theme, such as an API calling a system such as Open Policy Agent, so that documents returned are determined by rules configured by a security administrator. That policy would still involve using claims from the access token though.
EXAMPLE CODE
If it helps, here is some sample code of mine that show the type of approach when enforcing domain specific authorization rules. Typically you need to filter collections and check access to individual items.

OIDC generalized scopes

Currently building up a microservice for handling auth-related stuff using OIDC.
Now, we think about access control and how to be as future-proof as possible. This auth server is only used for first-party applications (3x SPA, 2x native mobile App). On mobile, we use the authorization_code grant. Each resource server validates the supplied token (access token as JWT) itself. But what happens when (in future), we add a service which needs its own scope to check (e.g. notifications:read)? As mobile app users are not used to logging in and out everytime (when we would update the requested scopes via an app update -> bad solution) is there any sweet solution to manage this scenario?
Per specification, it's possible to change the required scopes when refreshing a token but this is limited to require less scopes than originally requested and not more so that's not an option.
For example, Facebook is providing only four scopes for Instagram e.g. instagram_basic or instagram_content_publish. Zalando for example includes only a scope NORMAL_USER in their tokens whereas Wolt includes the users roles as a claim.
I think there is some confusion as this scenario is not covered directly by OAuth2 or OIDC. What are your thoughts about this?
There is one standard for doing OAuth 2.0 Incremental Authorization, but your challenge is to find a token provider that supports it or similar standards.
In a micro service architecture, the question is if you should use the access token from the authorization code flow everywhere, or if for service-to-service communication, you should use client credentials flow instead.
See also https://www.gmass.co/blog/oauth-incremental-authorization-is-useless/
It seems like you could use Token Exchange for that.
For example it could work like that - whenever your resource server gets a token without the notifications:read scope, issued before date x (so before you were issuing that scope) it performs an exchange with the authorization server and (if the server decides that it can perform the exchange) it gets a new access token that contains that scope. If the token was issued after date x you can safely assume that the token was not granted this scope.
Another solution would be to use claims for authorization decisions instead of scopes. The authorization server can issue e.g. a claim notifications_read: true, or something like that. Whenever you refresh tokens you can issue more claims in the new access token, the spec does not prevent that. Then your resource servers should check claims in the access token, they can ignore scopes. The resource server would just check whether the token contains the notifications_read claim with value true, or not. This solution gets a bit more complicated if you require your users to give consent to scopes, but as you said you're using this only for 1st-party, so I assume you're not using consent screens.
You can have a look at this free course - this topic of using claims in authorization is covered in part 4.

May an OAuth 2.0 access token be a JWT?

From what I can tell, the OAuth 2.0 specification is extremely vague in terms of what form an access token should take:
The token may denote an identifier used to retrieve the authorization
information or may self-contain the authorization information in a verifiable manner (i.e., a token string consisting of some data and a signature). Additional authentication credentials, which are beyond the scope of this specification, may be required in order for the client to use a token.
The access token provides an abstraction layer, replacing different authorization constructs (e.g., username and password) with a single token understood by the resource server. This abstraction enables issuing access tokens more restrictive than the authorization grant used to obtain them, as well as removing the resource server's need to understand a wide range of authentication methods.
Access tokens can have different formats, structures, and methods of utilization (e.g., cryptographic properties) based on the resource server security requirements. Access token attributes and the methods used to access protected resources are beyond the scope of this specification and are defined by companion specifications such as RFC6750.
(emphasis added)
The linked RFC6750 doesn't offer much further specificity. There is an example HTTP response body that shows:
{
"access_token":"mF_9.B5f-4.1JqM",
"token_type":"Bearer",
"expires_in":3600,
"refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA"
}
This seems to indicate that the access_token can be opaque ASCII text such as an encoded JSON Web Token (JWT)
From my perspective, it seems like JWT-as-access_token has some desirable properties:
It's a known specification, with fairly wide adoption and client libraries available in many languages.
It allows for easy signing and verification using vetted cryptographic libraries.
Because it can be decoded to JSON, it would allow us to include metadata and information about the token within the token itself.
My questions are: First, is it permissible for the access token to be a JWT? Second, if it is permissible according to the spec, are there any additional considerations that would make using a JWT as an access token a bad idea?
A1: Using a JWT as an access token is certainly permissible by spec exactly because the spec does not restrict its format.
A2: The idea behind using a JWT as an access token is that it can then be self-contained so that the target can verify the access token and use the associated content without having to go back to the Authorization Server. That is a great property but makes revocation harder. So if your system requires a capability for immediate revocation of access, a JWT is probably not the right choice for an access token (though you can get pretty far by reducing the lifetime of the JWT).
As long as the Authorization Server and the Resource Server agree on what the access token means, it doesn't matter what their content is. So the only reason you could have a problem would be if you were using different libraries or frameworks when implementing those two servers.
Currently the OAuth Working Group is working on a JWT profile for OAuth 2.0 access tokens: JSON Web Token (JWT) Profile for OAuth 2.0 Access Tokens

OpenId Connect - 2 way exchange of tokens in spec?

Does OpenId support a two way exchange of tokens at any place in the spec? Specifically allowing both parties to share tokens with each other in some way so they can share services with each other?
I've looked through the spec, but can't see anything detailing any scenarios like this.
An app I'm working on has integrated itself with a trusted OpenId provider, we'll call Acme.
We'd also like to provide access tokens and refresh tokens to Acme, as they'd like to access features of our service as well.
It seems natural that during our interactions to get tokens from Acme, that we'd like to expose tokens to them.
Is this part of the spec in any way? Or is the only way to do this is to become a full identity provider ourselves?
You could include the tokens as part of a request object, see: http://openid.net/specs/openid-connect-core-1_0.html#RequestObject but that would depend on a pair-wise agreement with Acme since they'd need to handle the non-standaridzed request object contents.
The best way forward is to become a provider yourself so you can leverage all the features of the various flows without being dependent on a pair-wise agreement and accompanying implementation.
It sounds like you're confusing OpenID Connect and plain OAuth2 to some extent.
OpenID Connect is a specification for identifying end users to a client application, based on their authentication at the OpenID Provider. It's not clear from your question whether end users are even part of the picture, so even plain OAuth2 may not be relevant (unless you are just using the "client credentials" grant).
Neither spec says anything about mutual exchange of tokens. It would probably help if you describe the interactions you anticipate in more detail and which grants you expect to use. Who will authenticate to your identity provider and what would be a typical client application?

Resources