A Crash Course in the Assertion Framework for OAuth 2.0 Client Authentication and
Authorization Grants
It’s as exciting as it sounds
Audience
This article assumes you have a solid understanding of OAuth2.0, HTTP and JWT tokens, and are looking to get an overview of RFC7521. We will be covering how to use assertions (defined shortly) to authenticate clients and/ or procure access tokens.
We will be demonstrating using an example from RFC7523 and implementing JWT tokens as assertions.
If you’re not quite up to speed on OAuth2.0, I recommend reading through my previous articles, which I’ve compiled in a list here.
Argument
Before we go any further, here’s some core definitions: assertions, relying parties and authorization grants.
Defining Core Terms
An assertion is a collection of information for sharing identity and security information across security domains. A good example is a JWT token.
Normally assertions include a subject (who the assertion relates to), the issuer (who stamps their approval of the subject) and the context of when it’s valid (where and when it can be used). The exact requirements for our RFC are here.
In a JWT these could correspond to the iss
, sub
, nbf
and exp
claims (where nbf
is ‘not before’, or when it’s valid from).
How an assertion is retrieved, formed, and exactly what it looks like, can be different depending on the implementation. For the purpose of the spec we can assume we have obtained one somehow, as procuring assertions is outside the spec scope.
For the sake of the RFC, assertions must always be signed to prove their authenticity (which JWTs usually are).
The relying party is whoever is consuming the assertion. In our case it will be the authorization aerver.
An authorization grant is a set of intermediate credentials representing the authorization granted by a resource owner, which can be exchanged for access tokens. In this case it’s our assertion.
Now we’ve got the basics down, let’s outline the two use cases.
Client Authentication
There are two types of client in OAuth2.0: public and confidential. What separates the two is that confidential clients can keep a client secret. There is a step in the OAuth2.0 spec where confidential clients can authenticate to the authorization server to prove they are who they say they are.
Assertions can be used for this authentication step as they demonstrate that a client has access to a key, via the signature. This key (or key pair) forms the client secret.
The above is use case one. This is not the same thing as using an assertion to procure access tokens!
This authentication implementation can be used as part of other authorization grants that don’t rely on assertions at all! An example of using it alongside the authorization code grant is below:
POST /token HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&
code=n0esc3NRze7LTCu7iYzS6a5acc3f0ogp4&
client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&
client_assertion=ABChbW...[omitted for brevity]...ZT
Note the extra parameters.
Using Assertions to Get Access Tokens
The second use case involves how we get access tokens using an assertion. Let’s introduce one other entity, the secure token server.
The secure token server is a party separate to the client, which issues the assertion. This is synonymous with the issuer inside the assertion itself, and they should have the keys used to sign it.
Generally we assume there is a trust-relationship between the authorization server and the secure token server. This relationship can be manifest in the secure token server exposing the public keys used to sign assertions, and the authorization server being happy to use them for verifying signatures.
We use the regular /token
endpoint, with the grant type as a URI the authorization server has defined and knows the format of (for example urn:ietf:params:oauth:grant-type:jwt-bearer
). We attach the assertion to the assertion parameter and can optionally specify scopes. An example request is below.
POST /token HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded
grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer
&assertion=abcdeVydGlvbiBJc3N1ZUluc3RhbnQ9IjIwMTEtMDU
[...omitted for brevity...]aG5TdGF0ZW1lbnQ-PC9Bc3NlcnRpb24-
The authorization server then:
- Retrieves the issuer from the assertion and can use it to do things like get the required keys for checking the signature.
- Acknowledges they are issuing access tokens for the party in the subject field.
- Check the audience is the authorization server.
- Check the assertion is valid according to any fields it has specified (e.g.
nbf
orexp
).
Error responses are defined here, and the success response is the standard one as defined in the OAuth2.0 core spec. A pictoral representation is below.
Conclusion
And that’s it! It’s a tricky one to get your head round at the start, but knowing what assertions are conceptually, and separating out the authentication and procuring access tokens use cases, should help.