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.
Related
I want to implement a solution where having 2 apis which take data from one another restrict access to the exposed endpoints by scopes.
Let's say that api1 exposes two scopes. read-only and write-only. some of its endpoints will allow only one out of the two some will allow both. Same for api2.
What I don't understand is where are the scopes validated ? Or to be more specific how exactly can I limit access to my api based on the requestor allowed scopes ?
I can undersatnd that on the identity server both the api resource and client should be configured and for the client to allow it to request access for specific scopes configured for the api resource, but I'm missing some information about how to validate the scopes.
Are the allowed_scopes part of the access_token ? If so as being part of the access_token, the api resource for which the token was generated should like decript the token and get the scopes or how exactly does this process work ?
Your thinking is on the right lines. APIs receive access tokens and authorize requests in 3 main stages:
First verify the digital signature of the JWT
Second each API endpoint verifies scopes, using the scope array received in the access token
Thirdly more detailed authorization is done using claims
A common way to check scopes is to use attributes on each controller method. Eg in .NET you get some help from the framework and can do this. See also this tutorial for sone other options:
[HttpGet]
[RequiredScope(myscope)]
public IEnumerable<TodoItem> Get()
{
// Do the work and return the result.
// ...
}
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.
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
A simple scenario I have a typical architecture a client,authorization server(OAuth Server) and Resource Server.Client gets token from authorization server with client_credentials and sends token to resource server and it serves the request.So if I have 2 API's either the logged in user can access all or none based on valid or invalid token.
Is there a mechanism to grant access to 1 API ? The question is can token be API specific like it give access to 1 API and not the other.
The scope mechanism can be used to differentiate between permissions that are associated with the access token. E.g. there could be a scope for API A and one for API B. The client could ask for one of those scopes or both and the token would be valid for respectively calling both APIs or just one of them.
See also: https://www.rfc-editor.org/rfc/rfc6749#section-3.3 which doesn't say much about the semantics of scope but in practice a scope is almost always associated with a (set of) permission(s).
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)