How to specify audience for an OAuth2 access token? - oauth

I am confused that there seems to be no standard way to specify the audience for an access token when sending an authorization request to an authorization server.
OAuth2 specifies access tokens as opaque strings; there is only one mention of 'audience' in the spec, to say that access tokens could be 'audience-restricted'.
Many recent authorization server implementations seem to produce JWT access tokens, and JWT specifies the audience (aud) claim.
As far as I find:
- Auth0 uses an 'audience' parameter
- Connect2id uses a 'resource' parameter
- Identity Server uses a fixed issuer-based value for 'aud' claim, and assumes that scopes are enough - however, this does not fit all use cases.
- The excellent 'OAuth2 in Action' book shows an example with a resource server URI in the 'aud' claim, but doesn't say where it comes from.
So, how to get an access token for a specific audience (resource server, API,...) in a standard way?

I think you are right. There are a couple of guidelines available.
The OAuth 2.0 Authorization Framework: Bearer Token Usage
OAuth 2.0: Audience Information (draft-tschofenig-oauth-audience-00.txt)
OpenID connect a clear defined "aud" parameter as:
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.

"Proposed Standard" way of requesting an Access Token for a specific Audience/API/Resource Server is by using the resource query parameter on the Authorization Request.
When the "resource" parameter is used in an authorization request to
the authorization endpoint, it indicates the identity of the
protected resource(s) to which access is being requested.
resource
Indicates the target service or resource to which access is being
requested. Its value MUST be an absolute URI
RFC8707: Resource Indicators for OAuth 2.0
https://datatracker.ietf.org/doc/html/rfc8707#section-2

You mentioned the Tschofeniq draft in your comment on the accepted answer, but actually it looks like that doc is actually does support using the audience field:
The audience URI MUST be an absolute URI as defined by Section 4.3 of [3]. It MAY include an "application/x-www-form-urlencoded" formatted query component
In fact it speaks quite strongly that this step is important and that it should be done in exactly that manner:
Step (2): When the client interacts with the token endpoint to obtain an access token it MUST populate the newly defined audience parameter ...
So it seems Auth0 is probably on the right track with the direction they took. And as you pointed out in your comment, the aud field is for the response, not the request (common libraries like jsonwebtoken in NodeJs set fields like this (along with sub, jti, and iss) when you decode a JWT.

Related

Do I Pass the Identity Token in a Header or Body of a Post Request?

The access token and refresh token being in the header makes sense to me (from this answer), but I'm wondering the same thing for ID or Identity Tokens. Should those be:
Passed into the body of a post request?
Passed into some header (Authorization header is used by the access token)
Something else (I'm misunderstanding the purpose of the identity token)
A little more context, through SSO, I would like to take the claims of a user (present only in the Identity Token) and sign them up in my system. I can confirm I can do this easily by throwing the identity token into the body of the initial POST request (and validate the signature on the server), but wanted to check if I'm breaking some standard.
Thanks!
In principle you can pass the ID token assuming that:
the software that consumes and validates the ID token (Relying Party, RP) is part of the same application and security domain as the target system
the link between the RP and the target system is secure i.e. authentication of both parties and confidentiality of the communication is established
the target system indeed requires all of the information in the ID token, otherwise it would be better to apply minimal disclosure and pass only a subset of the information
Passing the ID token (or the subset of claims) in headers may work if the amount of data is relatively small, otherwise you may run into HTTP header length limitations. Using POST though has the downside of having to modify the application request in flight which may be harder and have side effects.
For completeness, the refresh token is never passed in a header and only sent to the Authorization Server / Provider by the RP in a POST request.

Should dynamic query parameters be present in the Redirection URI for an OAuth2 (Autorization Code Grant Type)

Sources such as this Okta sponsored site (see "Per-Request Customization" section) mention that the redirect_uri parameter of a autorization request SHOULD NEVER have a dynamic query part (ex: for session matching uses).
Quote:
The server should reject any authorization requests with redirect URLs
that are not an exact match of a registered URL.
Our OAuth AZ provider is BIG-IP F5. We are setting it up, and they seem to comply with the above view.
Our client is a web application built elsewhere, and they seem to not follow the above rule.
Here is a complete representation of the Authorization Endpoint (redacted):
https://ourownF5host.ca/f5-oauth2/v1/authorize?client_id=theIDofOurClient&redirect_uri=https%3A%2F%2FourClientAppHostname%2FClientRessource%2FRessource%3FSessionId%3D76eab448-52d1-4adb-8eba-e9ec1b9432a3&state=2HY-MLB0ST34wQUPCyHM-A&scope=RessourceData&response_type=code
They use a redirect_uri with a format similar to (I don't urlencode here, for simplicity's sake) : redirect_uri=https://ourClientAppHostname/ClientRessource/Ressource?SessionId=SOMELONGSESSIONID, with the SOMELONGSESSIONID value being DIFFERENT for each call.
We dug DEEP into RFC6749 (OAuth2), and found this in section 3.1.2.2:
The authorization server SHOULD require the client to provide the
complete redirection URI (the client MAY use the "state" request
parameter to achieve per-request customization). If requiring the
registration of the complete redirection URI is not possible, the
authorization server SHOULD require the registration of the URI
scheme, authority, and path (allowing the client to dynamically vary
only the query component of the redirection URI when requesting
authorization).
What I understand, and would like to validate here, is that the first source, Okta and F5 accept ONLY the first part of the rule above, and require the redirection uri to be COMPLETELY registered without any dynamic part.
Am I right to affirm that they (Okta and F5) DO NOT comply with the second part of the excerpt, citing that they should "allow(ing) the client to dynamically vary
only the query component of the redirection URI when requesting
authorization" ?
OR, is there any kind of official correction/evolution of the RFC6749, that warrants both companies design position ?
TL;DR:
No, the redirect uri must be static for security reasons. If the client needs to keep a state between the authorization request and its asynchronous response, use the OAuth 2.0 state parameter.
Long version :
RFC6749 (the initial OAuth 2.0 specification) has been published in 2012 and OAuth security landscape has evolved a lot since then.
RFC6819, an OAuth 2.0 security review from 2013 already mentioned that refusing dynamically crafted redirect uris was a good way to protect against XSS and client impersonation attacks.
OpenID Connect, from 2014, a commonly used extension of OAuth 2.0 with authentication capabilities, already takes that recommendation into account and mandates exact string matching for all redirect uris.
The current draft recommendation for OAuth 2.0 Best Security Practice confirms that by enforcing redirect_uris preregistration and mandating the use simple string comparison by the AS when validating the redirect_uri passed in the request. So a dynamic redirect_uri must not be used.
Your client definitely makes a wrong move by using the redirect_uri as a "state keeper" between the Authorization request and response, by using a dynamically crafted SessionID attribute inside the redirect_uri. OAuth2.0 has a dedicated authorization request parameter for that purpose, which is "state". The client should use it. The AS will append that state in the parameters of the redirect_uri when it issues the response, so the client will be able to find back this state inside the response.
The proper authorization request would be:
https://youras/authorize?client_id=your_client_id&response_type=code&state=SOMELONGSTATE&redirect_uri=https%3A%2F%2Fsomehost%2Fauthcallback
The response will look like:
https://somehost/authcallback?state=SOMELONGSTATE&code=anazcode
This way the redirect_uri is static, so a simple string comparison is enough to validate that uri on AS side. Any algorithm more complex than simple string comparison would be subject to security flaws.
It appears there's two things mixed up here: the URL you refer to:
https://somehost/authcallback?state=SOMELONGSTATE&scope=someobjecttype&response_type=code
suggests that you mixed up the Redirect URI (aka. callback URL, as suggested by the pathname in the URL) of the Client with the Authorization Endpoint of the Authorization Server.
Only the Authorization Endpoint would take parameters as suggested and may contain e.g. a dynamic state value. The Redirect URI of the Client would not contain e.g. response type.
A redirect_uri parameter can be added to the the authorization request, which would then have to be matched in the way that you described. After confirming the match, the Authorization Server will redirect back to the Redirect URI, adding the code and state parameters.
Update (after the question changed):
OAuth 2.0 RFC6749 allows a dynamic (SessionId) parameter though it is not considered best practice. If however your client is an OpenID Connect Client, this is not allowed since the OpenID Connect spec (a "profile" of OAuth 2.0) locks down the Redirect URI matching to "exact", in which case you'd have to configure all possible SessionIds.

Is it OK to include the OAuth scopes inside a JWT?

I am adding an OAuth authorization server endpoint to my existing application. I am planing to issue JWTs from the OAuth token endpoint.
When a token issued for specific OAuth scopes, it looks better to embed the scopes for which the token is issued inside the token itself, because it is easier to validate whether the token has access to perform a certain action by looking at the token, when the client uses the issued token later to perform some action.
But, the standard claim fields of a JWT doesn't seem to include a suitable field to stamp the OAuth scopes.
So, would it be OK to include the scopes as custom claims in the JWT? Is there any other way to embed the scope details in the JWT?
JWT specification - RFC7519 provide you the ability to insert and use non-standard/registered claims. This is highlighted 4.3. Private Claim Names section of the specification.
A producer and consumer of a JWT MAY agree to use Claim Names that
are Private Names: names that are not Registered Claim Names
(Section 4.1) or Public Claim Names (Section 4.2). Unlike Public Claim Names, Private Claim Names are subject to collision and should
be used with caution.
Also, if you are after standard registered claims, they can be found here - https://www.iana.org/assignments/jwt/jwt.xhtml
Alternatively, if you are only interested to use standard claims and use only them with JWT Access Token (I assume JWT you refer is an access token), then you can define a token introspection endpoint and put scope values to its response. Scope is defined as a standard response parameter to introspection response
There is now JSON Web Token (JWT) Profile for OAuth 2.0 Access Tokens draft (and probably soon standard) which many already use in practice. In section 2.2.2 it explicitly states that:
If an authorization request includes a scope parameter, the corresponding issued JWT access token MUST include a scope claim as defined in section 4.2 of [TokenExchange].
All the individual scopes strings in the scope claim MUST have meaning for the resource indicated in the aud claim.
So not only that it is allowed to have scope claim, but it is even required if the request had one.

Oauth 2.0 authorization using JWT

I am implementing in web api 2 authorization using JWT token and I am new to this space.
I am stick to the purpose of generating AudienceId and AudienceSecret why I need them ?
From the perspective of OAuth, the tokens are opaque objects and does not contain 'audience' claims. If you use JWT tokens, then you can refer to JWT specificacion RFC7159
4.1.3. "aud" (Audience) Claim
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 intended use of audis to identify intended recipients of the token. Its use is optional and depends on the context of the application. May be in the documentation of your Oauth2 server is specified the purpose
Take also a look to this detailed answer about this topic

How can I extract the OAuth consumer key from a Rails request?

When an OAuth signed request is made to a Rails 3 app, I can see the OAuth consumer key in amongst the other values in request.headers["HTTP_AUTHORIZATION"]. What is a better way to access it? I'm using the OAuth gem.
According to this section in the OAuth specification, the Authorization header is the preferred way of sending OAuth protocol parameters. The specification does make allowances for sending protocol parameters in a form encoded body or in the request URI, if the request meets certain requirements.
To answer your question: parsing the Authorization header is a must for any OAuth provider. But you may also look for it (and other protocol parameters) amongst "normal" parameters, you will never find them in more than one place,

Resources