Oauth 2.0 authorization using JWT - oauth-2.0

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

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.

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.

How to specify audience for an OAuth2 access token?

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.

What is the correct way to use access_token?

I'm trying to use OAuth. In this example the provider was Windows Live. The redirect returned this fragment. I have added line breaks before the ampersands to make it a bit easier to read.
access_token=EwAwA61DBAAUGCCXc8wU/zFu9QnLdZXy%2bYnElFkAAQcQQB3c7oVYQmQhyeTOiw1Tp5iA7cjrLJbEnvXVoDlu48mjv7WX35RRIK3L3miAQEUrn5ZVNRSUV8dqiZi4kIko93k2bODqpIY7r/nBRmnTTbInajZm0iF1FLjXaFJGzM/XJN4jZiZUtipwaNu66cSwbEhNVUWwZufHjE7SNDUQze3/ciGP9c%2bTampSUS23u%2bcuKrCbj8jPhFIj2Tbritf83YcVaXLJHpEYVz2a1GKHm8/TPot2MgcjD3yBOBd5b/QBImASEcdOpouiYIshi1Ddy20iYL1Jv6JRpPExeWd8q9sEfk4a%2btMHIPFJ%2bdy0e6X9nRMjlx%2bHP0FhUrOp4rADZgAACD41pKeivbukAAIVEy964MrcJsT6MwfHHf54bi9Nfhek/vARUG32qt1HId/3GgYDKcXblAk6I7qW%2boywDMa%2bck59pJms7/pEGqSkLtY%2b5M86%2bWvSG9bNAJWfQnKT1re5L4AxpbJ2J7JOw9md%2byBnt9I3hk%2bQGoY4ZoSMTtZ2QOxIH0rfgxVqrebUjAcCf1AIl7yBusgF1zJITPTBX1fLaEw48VjXjNygQq/N82%2baKZhU2ZMBTtUzgnod4SMrb/IOaQsDF6prVTihGHae6rbRL/Ul4C/au59NAijEBB9evjM6PxSMMpMmag6VTXdVeLeCBFitFwcjtRUH38yIuhPGalBnRTVHyLpm8cS06mrQM2n5j9XnMFBtQzEQEtdvtOsUkIgpVYmqZE38CEh9YAjJBxG1Xo9Pdz/DnHflfc3PWtO1xMZsP/krBMQFxQRTPBOiNv%2bH2DPF1TED35iW%2bS5VDbxjSur1dCVAPqv3Vbduia1moJ1AUYPm9P7%2bcY%2bIV3skuz4Dzk0zQPgU3h7N6zPwr0oi%2bNe548sk6Cqq/wbF7oV6ytuAc0fbedf49I7QA8x8BEruePwNWj2N6v2vJQqQm6fOC%2by7ZQSsJ9830hD6E5yp4YVht%2bux%2b8wu%2bDQ9x/VB6BXLNC%2b4Q2aIhDQmui/JMrgHXgo2okv9FywwVQdaSLXVasfrCVmqzDwGFhIC
&token_type=bearer
&expires_in=3600
&scope=wl.signin%20wl.emails
&user_id=AAAAAAAAAAAAAAAAAAAAAB1EauoOQMnYy_bu42gkx90
&state=STATE
and I parsed that into name value pairs applying decodeURIcomponent to each.
That gave me an access_token value of
EwAwA61DBAAUGCCXc8wU/zFu9QnLdZXy+YnElFkAAQcQQB3c7oVYQmQhyeTOiw1Tp5iA7cjrLJbEnvXVoDlu48mjv7WX35RRIK3L3miAQEUrn5ZVNRSUV8dqiZi4kIko93k2bODqpIY7r/nBRmnTTbInajZm0iF1FLjXaFJGzM/XJN4jZiZUtipwaNu66cSwbEhNVUWwZufHjE7SNDUQze3/ciGP9c+TampSUS23u+cuKrCbj8jPhFIj2Tbritf83YcVaXLJHpEYVz2a1GKHm8/TPot2MgcjD3yBOBd5b/QBImASEcdOpouiYIshi1Ddy20iYL1Jv6JRpPExeWd8q9sEfk4a+tMHIPFJ+dy0e6X9nRMjlx+HP0FhUrOp4rADZgAACD41pKeivbukAAIVEy964MrcJsT6MwfHHf54bi9Nfhek/vARUG32qt1HId/3GgYDKcXblAk6I7qW+oywDMa+ck59pJms7/pEGqSkLtY+5M86+WvSG9bNAJWfQnKT1re5L4AxpbJ2J7JOw9md+yBnt9I3hk+QGoY4ZoSMTtZ2QOxIH0rfgxVqrebUjAcCf1AIl7yBusgF1zJITPTBX1fLaEw48VjXjNygQq/N82+aKZhU2ZMBTtUzgnod4SMrb/IOaQsDF6prVTihGHae6rbRL/Ul4C/au59NAijEBB9evjM6PxSMMpMmag6VTXdVeLeCBFitFwcjtRUH38yIuhPGalBnRTVHyLpm8cS06mrQM2n5j9XnMFBtQzEQEtdvtOsUkIgpVYmqZE38CEh9YAjJBxG1Xo9Pdz/DnHflfc3PWtO1xMZsP/krBMQFxQRTPBOiNv+H2DPF1TED35iW+S5VDbxjSur1dCVAPqv3Vbduia1moJ1AUYPm9P7+cY+IV3skuz4Dzk0zQPgU3h7N6zPwr0oi+Ne548sk6Cqq/wbF7oV6ytuAc0fbedf49I7QA8x8BEruePwNWj2N6v2vJQqQm6fOC+y7ZQSsJ9830hD6E5yp4YVht+ux+8wu+DQ9x/VB6BXLNC+4Q2aIhDQmui/JMrgHXgo2okv9FywwVQdaSLXVasfrCVmqzDwGFhIC
As I understood it, at this point all I have to do is add a header Authorization: Bearertoken value but doing so for a route protected by `[Authorization] produces 401 Unauth with a type of Basic. This leaves me at a bit of a loss as to how to proceed.
Looking at the browser debug info I see
WWW-Authenticate: Bearer error=invalid_token
Does the token being invalid mean this is an inappropriate token or that it can't be parsed as a token?
Is my methodology so far correct?
Is there some kind of server configuration I need to make?
Suggested next steps?
The Access token looks a bit like Base64 but it's not valid base64, I checked. Just thinking about the nature of a token, it's probably just the claims encrypted with the token issuer's private key. If that were so you could check the integrity of a token by decrypting the token using the issuer's public key, but I can't see how to use this observation to figure out why I have a 401.
Update
This is the startup.cs code that introduces token checking
app.UseJwtBearerAuthentication(new JwtBearerOptions
{
SaveToken = true,
TokenValidationParameters = tokenValidationParameters
});
and this auth0 web page cannot decode my token as a JWT token. Further reading suggests that a JWT token has three dot-separated sections each base64 encoded, and this is simply not present in the tokens I'm receiving from both Windows Live and Google (I've tested with both now).
So perhaps I need to restructure the token request if I want JWT tokens. More on this next episode. Feel free to write the next episode as an answer, if you know what I ought to be doing, endpoint and parameters etc. This other question What is the difference between id_token and access_token in Auth0 appears to be salient.
An access_token is what is says on the box - a token for access to a particular resource.
A JWT is an identity token. To get one of those, what I need to do is
use this endpoint: https://login.microsoftonline.com/common/oauth2/v2.0/authorize
specify a response_type of id_token
Include a nonce
Specify a scope of openid.
But returning to the question of how to use an access token, you use it as a bearer token in the authorization header in a requestion to the provider's endpoint for the scope in question, eg wl.email

OAuth2 returning JWT in place of access_token

I am currently in the process of building an OAuth2 provider using the bshaffer PHP library here.
I've found IETF draft specifications that outline the implementations that specifically call out the usage of JSON Web Tokens as an authorization grant and client authentication.
The implementation that interests me however is returning a JWT in place of the regular access token, as seen here. In case of dead link, the access token response is pasted below.
{
"access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpZCI6IjYzMjIwNzg0YzUzODA3ZjVmZTc2Yjg4ZjZkNjdlMmExZTIxODlhZTEiLCJjbGllbnRfaWQiOiJUZXN0IENsaWVudCBJRCIsInVzZXJfaWQiOm51bGwsImV4cGlyZXMiOjEzODAwNDQ1NDIsInRva2VuX3R5cGUiOiJiZWFyZXIiLCJzY29wZSI6bnVsbH0.PcC4k8Q_etpU-J4yGFEuBUdeyMJhtpZFkVQ__sXpe78eSi7xTniqOOtgfWa62Y4sj5Npta8xPuDglH8Fueh_APZX4wGCiRE1P4nT4APQCOTbgcuCNXwjmP8znk9F76ID2WxThaMbmpsTTEkuyyUYQKCCdxlIcSbVvcLZUGKZ6-g",
"client_id":"CLIENT_ID",
"user_id":null,
"expires":1382630473,
"scope":null
}
It returns a JWT in place of the regularly generated access token for the normal authorization grants. Client and User credentials grants are the more important for me as we are only dealing in 1st party API access.
This implementation seems to be ideal, because I do not need to maintain a store of generated tokens, limiting the amount of infrastructure that is required. At some point if we open the API to third-parties we would need a key-store for the various pub/priv keys to validate each client's tokens, and to limit the risk if some nefarious party stole the encryption key.
I feel this is a good implementation relying on asymmetric encryption and SSL/TLS. However are there potential security risks I've missed?
The signature on the JWT will only protect any claims inside the token from tampering, but cannot protect claims external to the token. Therefore, the expires field in your structure is not protected and can be tampered with.
To protect from tampering, you want to use the exp claim.
Two valid solutions are:
double check expires against exp
drop expires and just use exp
You might prefer one over the other depending on your requirements. Personally, I'd keep it simple and go with (2)

Resources