Is there any stadated way for replacing ID tokens of 2 authorization servers ?
For example, i have a service that you can login with an external ID Token but my service is also an authorization server and therefor i want to allow users exchange external ID Tokens with my service ID token.
OAuth2 specification defines following grant types:
authorization code
implicit grant
resource owner password credentials
client credentials
But it also supports defining additional grant types where required:
New authorization grant types can be defined by assigning them a
unique absolute URI for use with the "grant_type" parameter.
Per specification, new endpoints, parameters, response types and error codes may be defined to support the grant type extension.
When implemented, a client can make a request providing new grant type:
POST /token
grant_type=id_token&id_token=external-token&...
which would validate incoming token and issue your service's token.
Here are some links from oauth servers supporting custom grant types for inspiration:
https://oauthlib.readthedocs.io/en/latest/oauth2/grants/custom_grant.html
https://is.docs.wso2.com/en/latest/learn/writing-a-custom-oauth-2.0-grant-type/
https://identityserver.github.io/Documentation/docsv2/advanced/customGrantTypes.html
Related
Roles and terminology used in this question are the same as RFC 6749.
Description of the use-case
I want to allow a trusted OAuth client to ask authorization server to issue an access token on behalf of the resource owner without his consent (and without involving neither him nor his agent in the flow).
Investigations
As far as I know, there is not any grant matching this flow in RFC 6749, Section 4:
Grant
Suitable
Why
Authorization Code GrantRFC 6749, Section 4.1
No
It involves both Resource Owner and User-Agent.
Implicit GrantRFC 6749, Section 4.2
No
It also involves both Resource Owner and User-Agent.
Resource Owner Password Credentials GrantRFC 6749, Section 4.3
No
It might work if we knew the password of the resource owner, but we don't.
Client Credentials GrantRFC 6749, Section 4.4
No, but..
It doesn't involve the Resource Owner or his User-Agent but it's not granting access on behalf of a user.
Token ExchangeRFC 8693, Section 2
No, but..
It requires an initial token (named subject_token) which doesn't exist in my scenario.
Client Credentials
The Client Credentials grant is promising because it allows a client to access protected resources owned by a resource owner without involving him. Although, in my understanding, it's not on behalf of the resource owner. Quoting the RFC 6749, Section 4.4:
The client can request an access token using only its client credentials (...) when the client is requesting access to the protected resources under its control, or those of another resource owner that have been previously arranged with the authorization server (...).
Therefore, with access token returned by Client Credentials grant, it is for instance impossible to assign a sub claim value as defined in RFC 7662, Section 2.2: OAuth 2.0 Token Introspection > Introspection Response (cf. RFC 7519, Section 4.1.2: JWT ).
Token Exchange
This grant has been suggested by #Kaankom. See #Kaankom 's answer.
The RFC 8693 defines how to obtain a security token employing impersonation and delegation. It sounds like the perfect grant for my use-case but this grant requires as input a subject_token parameter which "represents the identity of the acting party." The RFC says:
Typically, this will be the party that is authorized to use the requested security token and act on behalf of the subject.
I don't have this token. However, I could maybe forge a new one (see Solution 5).
Non-standard solutions
Solution 1: A new OAuth grant
RFC 6749, Section 4.5 allow us to implement a new grant type. Similar to Client Credentials, this brand new grant would REQUIRE an additional parameter in his Access Token Request. This parameter would define the resource owner identifier for which the client will act on behalf of the resource owner.
Solution 2: Tweak the Client Credentials grant
Instead of implementing a new OAuth grant (cf. solution 1), we could instead add an optional parameter in existing Client Credentials grant. If specified, the authorization server should validate that the client is allowed to act on behalf of the requested resource owner (specified by the new parameter).
Solution 3: Tweak the Authorization Code grant
Using the Authorization Code grant, we could bypass steps A, B and C as defined in RFC 6749, Section 4.1 and let the client request an access token without having to add a code or a redirect_uri but with its client credentials and an additional parameter which define the resource owner.
Solution 4: Implement it out of OAuth
Browsing the internet, you might find implementations which are bypassing the OAuth mechanism and its access_token. For instance, in article "How to Convert from APIKey to OAuth 2.0 Client Credentials", they are using an extra HTTP header Acting-For on resource server calls.
Solution 5: Token Exchange grant with self-forged token
The Token Exchange grant requires a subject_token but (as far as I know) it doesn't define the policy that the authorization server SHOULD apply based on this token. Therefore, it would be theorically possible for the client to forge an unsigned JWT with the target subject (sub claim) and obtain a signed JWT in return. It looks promising but requires more investigation.
Notes
I intentionally not named the parameter used in solution 1, 2 and 3. However OpenID Connect Core 1.0, Section 3.1.2.1/Section 4 is defining an optional parameter named login_hint which "hint to the Authorization Server about the login identifier the End-User might use to log in". However sub might be another good proposal.
The Use Case you described sounds like impersonation.
Take a look at this: RFC 8693 - Token Exchange
You've not really described the use case / requirement, though I will describe something that may be in line with your use case and give you some ideas. Perhaps thinking more in terms of claims and API aauthorization will solve your problem in a standard way?
CORPORATE ASSETS USE CASE
Sometimes the assets don't belong to the end user and an entity has permissions to operate on a subset of users:
An investment bank may be able to update certain details for its employees in a wider trading system
A doctor's surgery may be able to update medical details for its patients in a system that contains nationwide data
In OAuth terms the bank / surgery would use the client credentials grant, and be identified by either a client ID or possibly a custom claim in the token issued.
If bank A tried to use their access token to update details for a trader at bank B, it would fail API authorization and they would receive an HTTP response with status 404, meaning data not found for caller.
It would not be natural though for bank A to get an access token for Jane Doe when updating that record, since that is not the caller identity. At an auditing level:
The Authorization Server would indicate that a token was issued to bank A
The API would indicate that the record for Jane Doe was updated by bank A.
The API could have many intricate domain specific rules around which type of data updates are allowed. These are usually managed in the API logic, while the access token contains only key caller identity information that the API can digitally trust before applying rules.
For more on this topic see our Claims Best Practices article.
Introduction
The following answer describes the flow, grant and parameters that may be used to allow a trusted OAuth client to obtain an access_token without the prior resource owner consent. This method is using the Token Exchange grant (defined in RFC 8693) in an impersonation scenario where the client would have to forge an unsecured subject_token and exchange it for a secured access_token. This method assumes that the authorization server produces and consumes JWT (RFC 7519). It would not work with opaque token.
Sequence Diagram
Step 1: Forge the initial JWT
In this first step, the client forges an initial unsecured JWT token (RFC 7519, Section 6). This JWT MUST contain at least the subject (sub) claim with, as value, the resource owner or another subject that the client want to impersonate.
Step 2: The client requests to exchange the initial unsecured JWT for a secured access token
The client exchanges the JWT forged in step 1 for a secured access token. According to RFC 8693 Section 2.1, the client sends a Token Exchange request with the following headers/parameters:
the Authorization header contains the client credentials (client id and client secret), following the Basic Authentication scheme.
the body parameter grant_type specify the grant type we want to use: token_exchange
the body parameter subject_token contains the JWT forged in step 1
the body parameter subject_token_type specify the subject token type we forged: an access_token (which is actually a JWT)
This is the bare minimum that the client MUST send. Although it SHOULD probably specify the audience, the target resource server and the list of scope.
Step 3: The authorization server returns the access token
According to its policy, the authorization server identifies the client as trusted and therefore allows to generate an access_token with unsecured subject_token in input. The subject defined in the subject_token (sub claim) is recycle in the generated access_token.
The authorization server will also add an Actor claim (act) according to RFC 8693, Section 4.1. The value of this claim is a JSON object with another sub key and the client id as value.
Step 4: The client requests a resource
In this example, the client requests a "personal" resource (/my/resource) with the access token. The sub claim inside the JWT is used to identify the "my" aka the subject.
Step 5: The resource is returned with an impersonation of the subject
That's it.
Disclaimer
I never implemented or tested this solution. It obviously requires a few changes in your authorization server and its policy. No security audit has been performed. Be careful with this flow. Confirmation from OAuth experts should be required prior to implementation.
From my understanding: -
The scopes that an oauth client can obtain are registered against the client on the Authorization Server .
The grant types that a client can use are registered against the client on the Authorization Server .
Resources are configured to allow requests containing access tokens that are associated with certain scopes.
Is there a mechanism in vanilla OAuth where the grant type in addition to the scopes are used when restricting an endpoint?
For example, given Client A with scopes=organizations, images and grant types=client credentials, auth code:
(at token creation)
For Client A to obtain an access token for ‘organizations’ scope, only client credentials grant type can be used.
For Client A to obtain an access token for ‘images’ scope, only auth code grant type can be used.
Or (when the resource endpoint it calls)
When the /organisation endpoint is called with an access token containing the expected ‘organization’ scope, only allow the request if the client credentials grant type was used to obtain the access token (fail if any other grant type was used).
When the /images endpoint is called with an access token for containing the expected ‘images’ scope, only allow the request if the auth code grant type was used to obtain the access token (fail if any other grant type was used).
As far as I know scopes are only limited by what is registered for a client.
The only way I can think of achieving the above would be to have two client registrations (e.g. b, c) for the same actual client (A) and configure client ‘b’ for client credentials grant type and organizations scope and client ‘c’ for auth code grant type and images scope.
Update
One option would be along OIDC lines to add a roles scope which would mean that the roles claims would be added to the access token. The access token could then be inspected to see whether the role is a third party (client credentials grant) or user (auth code grant).
I would still be interested to know if there is anything specifically built into oauth to restrict by grant type.
Tokens don't generally record grant information, and really the requirement is to be able to control access per application and based on the caller's rights.
I would always configure different OAuth Clients for different grant types - since these are different logical clients and can never share a session.
A few possible options:
OPTION 1. Use multiple APIs each with a different audience and configure different audiences for different OAuth Clients if that is supported by your Authorization Server
OPTION 2. An API endpoint can potentially check the client ID in access tokens against a list of allowed client IDs - though this is not a good long term option
OPTION 3. Use OAuth just to identify the caller and then look up rights for the caller that are stored and managed in your application data. This is almost always the best long term option.
OAuth only provides high level mechanisms for authorization and when you get into deeper domain specific authorization (eg what a role means or rules such as checking sufficient funds) it will not help you.
I like your idea of using roles, and from experience I would manage them like this:
Do high level OAuth authorization first via scopes etc
Identify the caller from the token's claims
Look up the caller's role(s) in your application data
Enforce the role's authorization rules in your API logic
According to RFC6749 Chapter 4.1.1: https://www.rfc-editor.org/rfc/rfc6749#section-4.1.1
In the specification of Authorization Request for Authorization Code grant,
Only client_id is required for Authentication. Since client type could be public, then that means anyone can get the Authorization Code, and then use it in Access Token Request - https://www.rfc-editor.org/rfc/rfc6749#section-4.1.3. Here you only need to supply client_id (Which is public), Authorization Code (Which can obtain with NO authentication), redirect_uri and grant_type (Not for authentication/authorization purpose), and then you will be able to obtain an access token!
My question is, why there is NO any mandatory authorization/authentication procedure for this type of grant, then what is the purpose of having this type of grant? Same thing in Implicit grant.
The client authentication is not mandatory only for the clients that are registered as public client like Mobile Native Application. The Mobile Application can not hold client secret securely, hence it is not mandatory in authorization code grant and implicit grant. The client application like web application which can hold client secret securely in the server, such clients should be registered as confidential client. The clients that are registered as confidential client should present both client id and secret for client authentication.
OAuth2 server issues an authorization code after user authentication and after user approving consent with delegating rights to the client (identified by client_id). The auth code is then sent as a parameter to a client's registered redirect URI. So I don't know what you mean by "anyone can get the Authorization Code".
Public clients should be used with PKCE OAuth2 extension. Which serves as a one-time password. So even if an auth code get stolen, it cannot be exchanged for tokens without knowing the code_verifier parameter of the token endpoint.
If an attacker creates a malicious application using someone else's client_id (pretending to be the client), the auth code will still be sent to the client's redirect URL. If the attacker gets hold of this URL handler, then it's probably a problem beyond the scope of the OAuth2 protocol.
Our Mobile Client App uses https://identityserver:port/oauth2/token service from Identity Server by passing the ClientID and ClientSecret with grant_type as “client_credentials” to generate the access token. The generated access token is used to invoke the API from ESB.
As per the implementation the ClientID and ClientSecret will be stored in the device.
For an example, ClientX requested for an Oauth Token which will have a certain expiry time. Can this token make as a unique for ClientX?
Currently all the upcoming client calls will get the same access token as its already generated from the request of ClientX. If a client is requesting a token very late it will get the same token with almost expiry time.
Is there a way to make this token unique for the Client?
In your case, if you use “client_credentials” as a grant type, resource owner is also the client.
Since this is a mobile application, once your mobile app gets the token it will be used until the expiry date and there will not be a necessity of changing it, because of mobile is belongs to a single user. Therefore the token would be same for same scope till it is expired.
Ex: BBC news mobile application.
If you need different access tokens, you need to use different scopes.
You will need different access token in case if different clients accessing the same API. In that case you may use “PASSWORD” grant type for a unique access token.
Ex: Purchasing a product using ebay.
So you should define your scope properly to identify the use of access token.
Find the following blog that will help you to guide to select your scope. [1]
[1] http://wso2.com/library/articles/2014/02/securing-your-web-service-with-oauth2-using-wso2-identity-server-1/
I will assume that mobile application instance is bound per user.
If you want to get different access tokens for every user bound to a session don't use client_credential grant type.
For example you have client-x and client-y both using client_credentials grant. Identity Server (Authorization Server) will give an access token for client-x and client-y since this is about authorizing client-x and client-y to access resource and not about authorizing a user. This means whatever user you have in client-x or client-y requesting access_token, they can get one (assuming they are authenticated).Vice versa, a user, even if authenticated both client and identity server cannot get an access token if the request comes from client-z (client-z is not registered in identity server)
If your Oauth 2.0 client is browser-based you can use implicit grant, if it is a server you can use either authorization grant or resource owner password credential.
The OAuth2 JWT Profile introduces the possibility to use JWTs both as authorization grant and as client authentication.
The JWT client authentication feature is independent of a certain grant type, and can be used with any grant type, also the client credentials grant.
However, using the JWT grant type seems to do exactly the same as using the client credentials grant with JWT client authentication, except that the syntax is slightly different.
In both cases the client contacts the token endpoint to get an access token:
POST /token.oauth2 HTTP/1.1
Host: as.example.com
Content-Type: application/x-www-form-urlencoded
grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=[JWT]
vs
POST /token.oauth2 HTTP/1.1
Host: as.example.com
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials&client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer&client_assertion=[JWT]
A slightly different perspective on the great answer by Josh C: as it happens both the client authentication and the grant credentials can be expressed as JWTs but the semantics behind them are different.
It is about separation of concerns: clients authenticate with a credential that identifies them i.e. they are the so-called subject whereas they use grants that were issued to them i.e. they are the so-called audience. Or as version 12 of the draft spec (https://datatracker.ietf.org/doc/html/draft-ietf-oauth-jwt-bearer-12) says:
The JWT MUST contain a "sub" (subject) claim identifying the
principal that is the subject of the JWT. Two cases need to be
differentiated:
A. For the authorization grant, the subject typically
identifies an authorized accessor for which the access token
is being requested (i.e., the resource owner or an
authorized delegate), but in some cases, may be a
pseudonymous identifier or other value denoting an anonymous
user.
B. For client authentication, the subject MUST be the
"client_id" of the OAuth client.
Probably very little. The way a client is identified and the way auth grants are requested are two different notions in OAuth, so the questions address those notions separately:
Can a client authenticate with an authorization server using a JWT? Yes.
Can a client make a grant request using a JWT? Yes.
The spec seems to hint that the separation is simply a design decision, deferring to policy makers to find what scenarios are valuable to them:
The use of a security token for client authentication is orthogonal to and separable from using a security token as an authorization grant. They can be used either in combination or separately. Client authentication using a JWT is nothing more than an alternative way for a client to authenticate to the token endpoint and must be used in conjunction with some grant type to form a complete and meaningful protocol request. JWT authorization grants may be used with or without client authentication or identification. Whether or not client authentication is needed in conjunction with a JWT authorization grant, as well as the supported types of client authentication, are policy decisions at the discretion of the authorization server.
One concrete possibility: The separation could allow for an authorization server to set up different policies along client types. For example, in the case of a public client (like a mobile app), the server should not accept the client creds grant type. Instead, the server could accept the JWT grant type for public clients and issue a token of lesser privilege.
Other than that, I would suppose that the design simply offers a degree of freedom for clients and servers to pivot around--keep this part of the existing handshake the same while migrating this part--as the need arises.