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 it's 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 identifies 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 it's 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 valid 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.