oauth2-server icon indicating copy to clipboard operation
oauth2-server copied to clipboard

BearerTokenValidator:validateAuthorization seems to incorrectly use the audience claim.

Open michaeldnelson opened this issue 6 years ago • 8 comments

        // Return the request with additional attributes
        return $request
            ->withAttribute('oauth_access_token_id', $token->getClaim('jti'))
            ->withAttribute('oauth_client_id', $token->getClaim('aud'))
            ->withAttribute('oauth_user_id', $token->getClaim('sub'))
            ->withAttribute('oauth_scopes', $token->getClaim('scopes'));

The appears to expect the client identifier as audience which seems to conflict with the bearer spec here. It's possible I am misunderstanding this spec as it is possible to reject a token based on the relationship between client_id and authorization server but that is not clear to me.

https://tools.ietf.org/html/draft-ietf-oauth-jwt-bearer-12#section-3

  1. The JWT MUST contain an "aud" (audience) claim containing a value that identifies the authorization server as an intended audience. The token endpoint URL of the authorization server MAY be used as a value for an "aud" element to identify the authorization server as an intended audience of the JWT. The Authorization Server MUST reject any JWT that does not contain its own identity as the intended audience In the absence of an application profile specifying otherwise, compliant applications MUST compare the audience values using the Simple String Comparison method defined in Section 6.2.1 of RFC 3986 [RFC3986]. As noted in Section 5, the precise strings to be used as the audience for a given Authorization Server must be configured out-of-band by the Authorization Server and the Issuer of the JWT.

michaeldnelson avatar Feb 18 '18 20:02 michaeldnelson

I can’t see anything in that spec that suggests that you can’t/shouldn’t use the client_id as the aud. Do you have any specific concern with this @michaeldnelson?

simonhamp avatar Feb 20 '18 23:02 simonhamp

I think you are right that this is not explicitly prohibited. Closer reading of the spec leaves this open for interpretation. I've just never seen it used this way. Personally my issue with this is that I validate the audience claim against $request->getHost(), this is a simple added layer of validation that doesn't require a database lookup. This is particularly useful if a token should be locked to a specific subdomain. Again this can all be validated with client id, it's just a little weird to me because I would consider that who is using the token, not the audience of the token. Additionally validation using the client id requires a db lookup, where host alone does not. But, as I said, I was wrong to assume this was "incorrect" it just was just cognitive dissonance for me and a challenge for my use case.

michaeldnelson avatar Feb 21 '18 01:02 michaeldnelson

There is a cid claim for this purpose it looks like.

https://tools.ietf.org/html/draft-ietf-oauth-token-exchange-12#section-4.3

4.3. "cid" (Client Identifier) Claim

The "cid" claim carries the client identifier of the OAuth 2.0 [RFC6749] client that requested the token.

The following example illustrates the "cid" claim within a JWT Claims Set indicating an OAuth 2.0 client with "s6BhdRkqt3" as its identifier.

{
  "aud":"https://consumer.example.com",
  "iss":"https://issuer.example.com",
  "exp":1443904177,
  "sub":"[email protected]",
  "cid":"s6BhdRkqt3"
}

michaeldnelson avatar Feb 21 '18 01:02 michaeldnelson

@michaeldnelson the last link you posted is for a draft version that has not been finalised yet I believe.

I think you might be right that the aud should be set to the authorization server endpoint. It looks like it has been incorrectly set to identify the client instead. We aren't, to my knowledge, officially implementing RFC 7523 at present but we are following the JWT RFC which confirms your assertion about the aud claim.

Altering this would be fairly tricky though as it would break BC. I think it probably is something that needs addressing but careful thought would be needed to not immediately invalidate all active access tokens.

Sephster avatar Feb 21 '18 14:02 Sephster

Thank you for taking the time to consider this issue :) I'll look forward to seeing how the project progresses.

michaeldnelson avatar Feb 21 '18 20:02 michaeldnelson

I agree with @michaeldnelson that we should use the cid claim for the client_id and that aud should actually be a list of the resource servers who are the recipient of the token. However, this would require the user to pass in a list of all resource servers (which may be the same server, or a very long list of servers). This would possible require adding a new Repository to keep track of resource servers.

For simplicity, and because aud for client_id is not strictly wrong according to the standard, although it hinders checking if the tokens are meant for that resource server (that would only be fixed if you specify the server in the request), I would not - at least soon - change the current behaviour.

Just my 2 cents.

christiaangoossens avatar Jul 13 '18 10:07 christiaangoossens

While the RFC is in draft it should not be used, it explicitly says so in the draft.

While eventually something will be standardised, oauth2-server should refrain from adding uncertain/uncomplete features. I've checked what the larger vendors use in their JWTs, as far as I could find nobody uses cid for the suggested purpose (yet).

If they use something it is usually referring to claims in an ID token. Which is OpenID spec, which is not supported (yet?) through the oauth2-server. For ID tokens the aud claim MUST be the client_id of the client requesting the token, but they also should not be used by resource servers to authenticate requests. http://openid.net/specs/openid-connect-core-1_0.html#rfc.section.2

I'm guessing that this ambiguity resulted from the original specs being less specific and because those tokens were typically used by resource servers that traditionally fairly tightly coupled to the same vendor that distributed the tokens, it didn't really matter. What is clear though, is that no large vendors are using the aud claim in access tokens to store the client_id, but you can always add your own claim to remedy that.

Maybe an option to correct this behaviour / allow people to add their own claims would be an option until this can be fixed in the default setting?

sg3s avatar Jul 16 '18 07:07 sg3s

Today while trying to get this discrepancy documented I reviewed the information in several specs and I think it is useful to clarify a few things.

The specification referenced by @michaeldnelson is something else The final version of the spec can be found here, and basically describes how to retrieve access tokens using JWTs from an authorisation server. It is used for 2 legged authentication scenarios (like the client credentials grant), usually where some kind of impersonation of specific users by a client without direct user input is used.

It is unrelated to the JWT contents in context of an access token used to communicate with a resource server.

The actual implemented specs neither explicitly define the JWT claim contents The two RFCs that this library does explicitly implement are "JSON Web Token" describing the generics of a JWT and the OAuth2 specific "Bearer Token Usage".

The first defines the generic usage of a small list of claims, the latter doesn't even mention JWT and predates it by years.

I've tried to find specifications that do touch upon this but could not find anything. Even OIDC does not go into this, probably because they consider it a problem of the resource server implementation. When you look at how explicitly id tokens are defined, it is a world of difference. If the wide range of implementations between authorisation servers is anything to go by, this might be a good candidate to make a specification for though.

JSON Web Token (RFC7519)

JSON Web Token (JWT) is a compact claims representation format
intended for space constrained environments such as HTTP
Authorization headers and URI query parameters.

What it does say about audience:

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, this can be an array, with values that are of type string or uri. It also states that all principals intended to process the JWT MUST be in this property. From the OAuth2 core spec we know that access tokens are usually opaque to clients, so they themselves should not need to process the token. The client could still also be an audience, but that probably means you actually want an (OIDC) id token which is explicitly meant for use by clients.

It is ultimately left to specific implementation to define exactly what the audience actually is.

Bearer Token Usage (RFC6750)

This specification describes how to use bearer tokens in HTTP 
requests to access OAuth 2.0 protected resources.
This document does not specify the encoding or the contents of the
token; hence, detailed recommendations about the means of
guaranteeing token integrity protection are outside the scope of this
document.

What it does say about audience (threat mitigation, summary):

To deal with token redirect, it is important for the authorization
server to include the identity of the intended recipients (the
audience), typically a single resource server (or a list of resource
servers), in the token.
Issue scoped bearer tokens:  Token servers SHOULD issue bearer tokens
      that contain an audience restriction, scoping their use to the
      intended relying party or set of relying parties.

This quite clearly defines the resource servers as the audience, within the scope of OAuth2 access tokens. So believe this to be the most usable information to base the library implementation upon. But the bearer token usage spec does predate the JWT spec by years.

Though, if a future specification would actually elaborate what is what in at least the generic claims that can be present in a JWT that should be leading (anyone have time for that?).

Conclusion The OAuth2 server should and does make a stance here as specifics in this area are left to implementations. Having the client id in the audience is not wrong per-se, but resource servers should be added (config array / resource server repository interface?) as audiences too.

That way resource servers can verify the tokens are intended for their usage, which is something they MUST do according to the combined specifications, when the aud claim is present.

sg3s avatar Sep 13 '18 14:09 sg3s