I am implementing OAuth 2.0 with JWT in my application and am having trouble deciding what to set as my aud claim as. A user will "login" to my client via my authentication server to gain access to my API (resource) server. I want my tokens to only be valid for use with a specific client and specific API.
When logging in from my client, I include it't client_id in the request, but in most implementations I've found, the aud is set to that client_id. I'm leaning towards including a customer audience_id field in my login request and then setting the aud in the token to an array of the client_id and the audience_id, but that feels like it just means that that token is valid for both those audiences, which makes me think I should just add a custom claim called client to specifically state that this token was created for a specific client.
I have not come across any implementations online that include both a client_id and audience_id(s) in an OAuth login request, nor do I see a reserved claim for client in the spec.
Am I missing something here?
What is best practice for specifically stating a different client_id and audience_id in a JWT?
The audience of the JWT is the Resource Server as that is where the token will be processed, i.e. verified, inspected and acted upon. From RFC 7519, https://www.rfc-editor.org/rfc/rfc7519#section-4.1.3:
The "aud" (audience) claim identifies the recipients that the JWT is
intended for. Each principal intended to process the JWT MUST
identify itself with a value in the audience claim.
[...]
The interpretation of audience values is generally application specific.
[...]
So best practice is that aud should identify the Resource Server.
The Client is only the presenter of the token and it is best practice (i.e. in OpenID Connect and some emerging OAuth 2.0 exension drafts) to use the azp (Authorized Presenter) for that claim. From http://openid.net/specs/openid-connect-core-1_0.html#CodeIDToken :
azp
OPTIONAL. Authorized party - the party to which the ID Token was
issued. If present, it MUST contain the OAuth 2.0 Client ID of this
party. This Claim is only needed when the ID Token has a single
audience value and that audience is different than the authorized
party.
[...]
So best practice is that azp identifies the Client.
Related
I am pretty new with these protocols, and I am having some trouble understanding something.
I am currently working on an application which API and Frontend is mine, I use azure identity platform to receive the tokens on the clientside and send the token to the server that validates the token using passport-azure-ad bearerStrategy. (I have my app registration for that purposes ofcourse).
The thing that I don't get, is that I missed correctly used the tokens I received from azure in my client and sent the ID Token to my API, it verifes it as a valid one and user is authenticated to perform the request sent.
But, as I read here https://learn.microsoft.com/en-us/azure/active-directory/develop/id-tokens, and in any other article about oAuth2 and openID, ID tokens are for UX stuff and client, while I should have used the access token in my request to my API.
But howcome the ID Token is also verified in my API? It makes no sense for me, or am I missing something?
And if so, is there any vurlnabilty in using Id Token as I did?
Thank you!
APIs should first validate the JWT access token, to check these fields have allowed values. An ID token will then fail the audience check.
JWT signature
Not expired / valid at this time
Issuer (a Microsoft ID)
Audience (eg api.mycompany.com)
Access tokens have scopes, whereas ID tokens do not. Every API endpoint should validate the received scope, eg to ensure that it has received the right type of token. This will also ensure that the API does not accept ID tokens.
So although some API tech stacks accept ID tokens, making the standard checks will ensure the right behavior. And the real API authorization is then done using claims, to apply your business rules.
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.
I am missing some understanding of OAuth2 access_token hope someone can explain or guide me to what I am missing.
I am using Microsoft Azure AD as an authentication provider for my application, I used the returned id_token after successful authentication to extend it with some additional data custom to my application (to facilitate authorization).
I am doing this throw JWT.sign, I decode the data from id_token and add data then I sign it using a secret key saved at the server.
My question is, can I do the same for access_token? When I tried to do so, I get unauthorized.
Am I doing something wrong? Or this is not possible? And why is this happening, I don't find any request made to MS to validated my new signed access_token.
You should never change tokens issued - this is not a correct thing to do. But your point about using domain specific claims is totally valid - all real world systems need these for their authorization.
OPTION 1
Some specialist providers can reach out at time of token issuance and contact your APIs, to get domain specific data to include in tokens. See this Curity article for how that works. I don't think Azure AD supports this though.
PRIVACY
It is best to avoid revealing sensitive data in readable tokens returned to internet clients. If you include name, email etc in ID tokens or access tokens this may be flagged up in PEN tests, since it is Personally Identifiable Information and revealing it can conflict with regulations such as GDPR.
Curity recommends protecting access tokens by issuing them in an opaque reference token format - via the phantom token pattern.
OPTION 2
An option that would work fir Azure AD is to adopt the following approaches:
Look up extra domain specific claims in your API when an access token is first received, then cache results for further API requests with the same access token. See this Azure AD Code Sample class of mine for some code that builds a custom ClaimsPrincipal. Note that the API continues to validate the JWT on every request.
If the UI needs extra domain specific claims then serve them from your API, which can return both OAuth User Info and domain specific data from its ClaimsPrincipal to the UI. See this API controller class for how that looks. Personally I always do this and never read ID tokens in UIs - which should also never read access tokens.
Applications interacting with Azure AD, receive ID tokens after authenticating the users. The applications use access tokens and refresh tokens while interacting with APIs.
The id_token is a JSON Web Token (JWT) which has user profile
attributes in the form of claims. The ID Token is consumed by the
application and used to get user information like the user's name,
email.
The Access Token on the otherhand is a credential that can be
used by an application to access an API.
So if you need application to access api, there the access token is used and you may follow the suggestion steps provided by Tiny Wang
Similar to id tokens, access tokens are also signed, but they are not
encrypted. As per IETF OAuth (RFC 6749) standard specification ,
access token can have different formats and structures for each
services whereas, id token should be JWT format.
To validate an id_token or an access_token, your app has to validate
both the token's signature and the claims. To validate access tokens,
your app should also validate the issuer, the audience, and the
signing tokens.
So in production application, you should get id token by specifying
“id_token+code” or “id_token+token” as response_type to verify
whether the authentication is correctly succeeded. It means it uses
the id_token for authentication and “code” to exchange access_token
to access the resource for authorization.
In short id_token is used to identify the authenticated user, and the
access token is used to prove access rights to protected resources.
Refer this for the information regarding access token and id token.
I know that the access token obtained from OAuth2.0 can be used to access protected resources.
OpenID Connect issues ID token and access token after authentication. And the spec says that the access token can be used to access userinfo endpoint to get additional user information.
One thing I'm not able to understand is, is there any difference between the access token obtained in #1 vs #2. If there is no difference then do we need OAuth2.0, if we implement OIDC.
You tend to just implement both OIDC and OAuth 2.0 together as a combined flow, by plugging in an Open Id Connect security library.
Eg For a mobile app it is common to plug in AppAuth Libraries, which would give you this behaviour:
An OAuth 2.0 authorization redirect using response_type=code
The Open Id Connect part is initiated by including scope=openid
You then get an authorization code (OAuth 2.0)
You then swap the authorization code for tokens
You get an access token (the OAuth 2.0 part)
You also get an id token (the OIDC part)
In practical terms OIDC introduces some standardisation that makes developing UI flows and dealing with access tokens in APIs easier, eg:
Metadata endpoint, to tell us where all the other endpoints live
JWKS endpoint, from which we can get the access token's public key
Typically in my own code I do not use the id token much at all. However, it is best practice to receive one, so that libraries such as AppAuth can make extra verification checks against received tokens.
If it helps, my Message Workflow Blog Post summarises some messages and use of endpoints.
This access tokens have different audiences ("aud" claim): the OAuth 2.0 access token is intended for resource server (i.e. API), and OIDC access token is intended for identity server itself.
As for me, they cannot be used interchangebly, but some examples (e.g. IdentityServer4) do that without checking the "aud" claim.
PS. The single access token can be used for both purposes if both audiences are included:
Each principal intended to process the JWT MUST identify itself with a
value in the audience claim.<...> In the general case, the "aud" value
is an array of case-sensitive strings, each containing a StringOrURI
value.
JWT doc
I'm working on implementing OAuth 2.0 JWT access_token in my authentication server. But, I'm not clear on what the differences are between the JWT aud claim and the client_id HTTP header value. Are they the same? If not, can you explain the difference between the two?
My suspicion is that aud should refer to the resource server(s), and the client_id should refer to one of the client applications recognized by the authentication server (i.e. web app, or iOS app).
In my current case, my resource server is also my web app client.
As it turns out, my suspicions were right. The audience aud claim in a JWT is meant to refer to the Resource Servers that should accept the token.
As this post simply puts it:
The audience of a token is the intended recipient of the token.
The audience value is a string -- typically, the base address of the
resource being accessed, such as https://contoso.com.
The client_id in OAuth refers to the client application that will be requesting resources from the Resource Server.
The Client app (e.g. your iOS app) will request a JWT from your Authentication Server. In doing so, it passes it's client_id and client_secret along with any user credentials that may be required. The Authorization Server validates the client using the client_id and client_secret and returns a JWT.
The JWT will contain an aud claim that specifies which Resource Servers the JWT is valid for. If the aud contains www.myfunwebapp.com, but the client app tries to use the JWT on www.supersecretwebapp.com, then access will be denied because that Resource Server will see that the JWT was not meant for it.
The JWT aud (Audience) Claim
According to RFC 7519:
The "aud" (audience) claim identifies the recipients that the JWT is
intended for. Each principal intended to process the JWT MUST
identify itself with a value in the audience claim. If the principal
processing the claim does not identify itself with a value in the
"aud" claim when this claim is present, then the JWT MUST be
rejected. In the general case, the "aud" value is an array of case-
sensitive strings, each containing a StringOrURI value. In the
special case when the JWT has one audience, the "aud" value MAY be a
single case-sensitive string containing a StringOrURI value. The
interpretation of audience values is generally application specific.
Use of this claim is OPTIONAL.
The Audience (aud) claim as defined by the spec is generic, and is application specific. The intended use is to identify intended recipients of the token. What a recipient means is application specific. An audience value is either a list of strings, or it can be a single string if there is only one aud claim. The creator of the token does not enforce that aud is validated correctly, the responsibility is the recipient's to determine whether the token should be used.
Whatever the value is, when a recipient is validating the JWT and it wishes to validate that the token was intended to be used for its purposes, it MUST determine what value in aud identifies itself, and the token should only validate if the recipient's declared ID is present in the aud claim. It does not matter if this is a URL or some other application specific string. For example, if my system decides to identify itself in aud with the string: api3.app.com, then it should only accept the JWT if the aud claim contains api3.app.com in its list of audience values.
Of course, recipients may choose to disregard aud, so this is only useful if a recipient would like positive validation that the token was created for it specifically.
My interpretation based on the specification is that the aud claim is useful to create purpose-built JWTs that are only valid for certain purposes. For one system, this may mean you would like a token to be valid for some features but not for others. You could issue tokens that are restricted to only a certain "audience", while still using the same keys and validation algorithm.
Since in the typical case a JWT is generated by a trusted service, and used by other trusted systems (systems which do not want to use invalid tokens), these systems simply need to coordinate the values they will be using.
Of course, aud is completely optional and can be ignored if your use case doesn't warrant it. If you don't want to restrict tokens to being used by specific audiences, or none of your systems actually will validate the aud token, then it is useless.
Example: Access vs. Refresh Tokens
One contrived (yet simple) example I can think of is perhaps we want to use JWTs for access and refresh tokens without having to implement separate encryption keys and algorithms, but simply want to ensure that access tokens will not validate as refresh tokens, or vice-versa.
By using aud, we can specify a claim of refresh for refresh tokens and a claim of access for access tokens upon creating these tokens. When a request is made to get a new access token from a refresh token, we need to validate that the refresh token was a genuine refresh token. The aud validation as described above will tell us whether the token was actually a valid refresh token by looking specifically for a claim of refresh in aud.
OAuth Client ID vs. JWT aud Claim
The OAuth Client ID is completely unrelated, and has no direct correlation to JWT aud claims. From the perspective of OAuth, the tokens are opaque objects.
The application which accepts these tokens is responsible for parsing and validating the meaning of these tokens. I don't see much value in specifying OAuth Client ID within a JWT aud claim.
If you came here searching OpenID Connect (OIDC): OAuth 2.0 != OIDC
I recognize that this is tagged for oauth 2.0 and NOT OIDC, however there is frequently a conflation between the 2 standards since both standards can use JWTs and the aud claim. And one (OIDC) is basically an extension of the other (OAUTH 2.0). (I stumbled across this question looking for OIDC myself.)
OAuth 2.0 Access Tokens##
For OAuth 2.0 Access tokens, existing answers pretty well cover it. Additionally here is one relevant section from OAuth 2.0 Framework (RFC 6749)
For public clients using implicit flows, this specification does not
provide any method for the client to determine what client an access
token was issued to.
...
Authenticating resource owners to clients is out of scope for this
specification. Any specification that uses the authorization process
as a form of delegated end-user authentication to the client (e.g.,
third-party sign-in service) MUST NOT use the implicit flow without
additional security mechanisms that would enable the client to
determine if the access token was issued for its use (e.g., audience-
restricting the access token).
OIDC ID Tokens##
OIDC has ID Tokens in addition to Access tokens. The OIDC spec is explicit on the use of the aud claim in ID Tokens. (openid-connect-core-1.0)
aud
REQUIRED. Audience(s) that this ID Token is intended for. It MUST contain the OAuth 2.0 client_id of the Relying Party as an audience value. It MAY also contain identifiers for other audiences. In the general case, the aud value is an array of case sensitive strings. In the common special case when there is one audience, the aud value MAY be a single case sensitive string.
furthermore OIDC specifies the azp claim that is used in conjunction with aud when aud has more than one value.
azp
OPTIONAL. Authorized party - the party to which the ID Token was issued. If present, it MUST contain the OAuth 2.0 Client ID of this party. This Claim is only needed when the ID Token has a single audience value and that audience is different than the authorized party. It MAY be included even when the authorized party is the same as the sole audience. The azp value is a case sensitive string containing a StringOrURI value.
Though this is old, I think question is valid even today
My suspicion is that aud should refer to the resource server(s), and
the client_id should refer to one of the client applications
recognized by the authentication server
Yes, aud should refer to token consuming party. And client_id refers to token obtaining party.
In my current case, my resource server is also my web app client.
In the OP's scenario, web app and resource server both belongs to same party. So this means client and audience to be same. But there can be situations where this is not the case.
Think about a SPA which consume an OAuth protected resource. In this scenario SPA is the client. Protected resource is the audience of access token.
This second scenario is interesting. RFC8707 "Resource Indicators for OAuth 2.0" explains where you can define the intended audience in your authorization request using resource parameter. So the resulting token will restricted to the specified audience. Also, Azure OIDC use a similar approach where it allows resource registration and allow auth request to contain resource parameter to define access token intended audience. Such mechanisms allow OAuth adpotations to have a separation between client and token consuming (audience) party.