OAuth client credential grant and token introspection with Ping - oauth-2.0

Using Ping as OAuth authorization server, when introspect access token issued with client credential grant type, the resulted output does not include "sub" claim. Is there a way to configure Ping to include some functional ID or technical ID in the "sub" claim?

If you have PingFederate 9.0 and up, the Client Credentials grant mapping contract is customizable (see Version History here) for these purposes.
To add a "sub" claim, add the attribute "sub" to your Access Token Manager instance's contract. Then, in your Access Token Mapping (under Grant Mapping in the administrative console) you can add a mapping for the Client Credentials context for your Access Token Manager instance. You will then be able to define the fulfillment logic (as you say to some ID value) there. For more details, see: https://support.pingidentity.com/s/document-item?bundleId=pingfederate-92&topicId=adminGuide%2FaccessTokenMapping.html

Related

What is the OAuth flow to generate access token without consent from resource owner?

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.

Openid Connect standard way for exchanging ID Tokens

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

Restrict access to resource based on grant type in addition to scope

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

OAuth2 Roles in OIDC

In OAuth2 protocol, Client (RP in terms of OIDC) application obtains an access token, which enables it to use different services (Resource server role) on behalf of a Resource Owner.
On the other hand, in the OpenID Connect protocol, Client obtains 2 tokens (access and id token). Now this Client can use the access token to fetch user claims from the UserInfo endpoint.
Does OP (Authorization server) play role of a Resource Server here (in terms of OAuth2), and Client fetches user data on behalf of a user?
How is ID token used by the Client? Does Client pass this ID token to the Resource Owner's user agent (Browser) and then, user agent stores this token to enable SSO (cookie)?
Does Client (e.g. different one than the one that obtained the ID token) has to verify the token every time user accesses it (call OP to verify it), or Client does this only first time it gets accessed by this token and then creates security context which enables it to eliminate this request for verification at OP every time? In this case, how could this security context be implemented?
What is the access token used for, except for fetching user claims and why is it sent along with ID token, when Client could use ID token to access UserInfo endoint?
First of all you must understand the purpose of tokens. Access token is a token that is good enough to access a protected resource on behalf of the end user. It is defined by OAuth 2.0 authorization framework. Now having an access token does not authenticate the end user. it simply authorize the client application to access a resource. OpenID Connect introduce the ID Token. Now this token is to be consumed by your client application. Protocol define how this to be done and if valid, your client application can authenticate the end user.
Q: Does OP (Authorization server) play role of a Resource Server here (in terms of OAuth2), and Client fetches user data on behalf of a user?
Partially correct. According to the protocol document, userinfo endpoint acts as OAuth 2.0 protected resource.
The UserInfo Endpoint is an OAuth 2.0 Protected Resource that returns Claims about the authenticated End-User. To obtain the requested Claims about the End-User, the Client makes a request to the UserInfo Endpoint using an Access Token obtained through OpenID Connect Authentication.
Q: How is ID token used by the Client? Does Client pass this ID token to the Resource Owner's user agent (Browser) and then, user agent stores this token to enable SSO (cookie)?
As mentioned previously client must validate the id token and based on that it can authenticate the end user. ID token is not connected with SSO.
Q:Does Client (e.g. different one than the one that obtained the ID token) has to verify the token every time user accesses it (call OP to verify it), or Client does this only first time it gets accessed by this token and then creates security context which enables it to eliminate this request for verification at OP every time? In this case, how could this security context be implemented?
If you are using ID token to be consumed from a protected endpoint, then token receiving party should validate it before accepting it. One may choose to create a session after a proper token validation (session must not extend the life time of the token).
Q: What is the access token used for, except for fetching user claims and why is it sent along with access token, when Client could use ID token to access UserInfo endoint?
Access token is the token your should use to access OAuth 2.0 protected resources. Once the endpoint received it, endpoint can validate the access token against token introspection endpoint exposed by the authorization server (Protocol definition of introspection). And with Openid Connect, defining of userinfo endpoint let any party with valid id token to consume it.
I don't see how you can be confused about that if you've read the RFCs.
You want to think of identity as a "resource" service? fine, but the authentication for this service is different than for RPs, so what's your point?
The Client exists in the User Agent (we're talking about SPAs, right?). If the ID token is in the Client, then it's in the UA (the reverse is not true). If you're thinking of server-side clients, then there is no need to forward the ID token to the UA, unless you want the UA to pass it on to another Client (e.g. for SSO). There are SSO schemes that use the ID token for convenience, but that's not the stated purpose of the ID token.
The whole point of JWS is that you don't need to call the OP to verify a token. You just verify the signature. That may be done by any Client, whether they're the original recipient of a token, or they get it later. Furthermore, the ID token is not meant to authenticate the user. Using it for SSO requires some other form of security, such as storing a related secret in an HTTP-only cookie that will not be seen by the Client. Anyway, even if you use the ID token for SSO, then the ID token is sent only in the login request. After that, the Client will get its own access token for authentication and will not use the ID token again.
The access token is typically short-lived (which means the Client has to contact the OP regularly, which allows the OP a chance to revoke access). The access token is sent with every authenticated request, so it should be small (i.e. not contain user information that is not useful for authentication).

Azure AD OIDC ID Token for Service Principal

Is it possible to obtain an OAuth2 id_token for an Azure AD Service Principal?
I can go through the client_credentials flow against the /token endpoint, but that only yields an access_token. Is there a way for me to get an id_token as well, like I do for an interactive user?
No. You need to go through a flow which involves a service principal and a user.
Client credentials flow only involves the service principal, so the access token only contains its info. Id tokens are only given when there is a user context.
So, for an Id token, you need to use one of these flows:
Authorization Code
Implicit
Device code
On-Behalf-Of (API calling another API)
Resource Owner Password (though I don't recommend this one)
Ultimately, why do you need an Id token? The access token already contains who the calling app is. It should contain an appid claim, which is the client Id for the app.

Resources