OAuth 2.0 - Serverless Token Issuance
13. November 2018 (I also published it on the 6th Nov 2018 here)

Hello everybody!

It is long ago since I have posted anything on this site. Now I am back and I would like to propose an OAuth flow where OAuth clients issue token themselves instead of receiving them from an authorization server.

In the week of 22. October 2018 I attended IIW 27 (Internet Identity Workshop) in Mountain View/ California. IIW is the place to go when it comes to identity related topics such as OAuth, OpenID Connect and many others. At this IIW a few topics came up that I have thought about in the past, too. For example, "how to prevent data leakages where access_token are lost?". Interestingly, the week before I went, I had a meeting with a few colleagues of mine. In that meeting I asked the following:

What, if the client issues the access_token itself?

This is my high level thought:

If a client is known by a trusted authorization server, it should be good enough for any resource server to accept a token that was issued by the client, if that token is based on a grant that was given to the client by the trusted authorization server!

Something like this:

Dear Resource Server, I, the Authorization Server, vouch for the authenticity of the client and you may accept its request!

Pre-Requisites

To make this happen a few pre-requisites need to be satisfied:

  1. the client must be able to validate and create JWT
  2. the client is registered at the authorization server
  3. the client has registered potential SCOPEs it may use at the authorization server
  4. the client has registered a public cert or a jwks_uri at the authorization server
  5. the client has registered its redirect_uri(s) at the authorization server

How does the message flow look like?

Here are the three main steps in a default message flow, assuming the client registration has been done.
(for more or less all details, please see this sequence diagram):

  1. A client requests an authorization grant, similar to requesting an authorization code today. But instead of receiving a plain text string as 'code' it receives a 'grant'. This 'grant' is a JWT, signed by the authorization server.
  2. The client generates an access_token itself, which is also a JWT. This JWT includes the grant and other details. The JWT is signed by the clients private key and includes the public cert in the JWT header 'x5c'.
  3. When the resource server receives the access_token it decodes it and validates the 'grant' first. Once that is done it validates the JWT access_token. If it is valid, it accepts the request.

Main advantages of this approach

After all these explanations, here are my personal highlights:

  1. The authorization server does not need to support a token endpoint and with that no grant_types. This massively simplifies the overall system
  2. The client can proof to the resource server that it 'owns' the given grant
  3. The 'proof-of-possession' check does not require mutual TLS connections. This removes any complications where, for example, loadbalancers terminate SSL connections. I know, some of you may say: 'The token could still be given by a client that stole this token'. I know, but, at least for now, I think this is good enough
  4. The 'grant' and the 'access_token' have 'issued at' timestamps. It is entirely up to the resource server to accept token by their calculated age (without exceeding 'max_age')
  5. Resource servers may accept requests of completely unknown clients. Self-signed certificates can be used by the client for signing their JWT-based access_token
  6. The 'grantId' represents an active 'consent'. The AS /introspection endpoint can be used to check if a 'consent' has been revoked. Since this 'grantId' has no other purpose it is a 'low-risk-item'
  7. No access_token are persisted at any authorization server. Data leaks are not possible (at least not in a large scale)

What is the main difference at the authorization request?

For once, the client uses response_type=grant, which is completely new. In addition, the request may include a kid (KeyID). This is used to tell the authorization server which public certificate this client will use during this session. The parameter target contains the target endpoint (resource) the client wants to consume. For the moment, this may be omitted or specified for particular use cases.

The other difference is the response. It contains a grant. It, more or less, contains, what an oauth introspection endpoint would return. One of the very important values inside of it is the cnf.x5t#S256 value. It can later be used as proof-of-possession at the resource server.

Another new value is the grantId. Whenever a resource owner grants a client access to resources, this is created at the authorization server. If a resource owner would revoke the grant for this client, that value would be invalidated. This decouples grant (or consent) from any access_token or refresh_token and has no value of any sort otherwise. Resource servers may provide this value to the authorization servers introspection endpoint to verify that this 'grant' is still active.

Content of the 'grant':

The grant should contain all details that are required by a resource server to validate a clients request as 'valid'. Therefore it should contain the claims listed below:

NOTE: The grant may also include a 'sub' (subject) or an id_token of the granting user. This depends on the use case and/or requested SCOPEs!

Other changes at the authorization server include an updated /introspection endpoint to support validations of client-side issued access_token. The authorization server also has to create and issue the 'grantId'.

What is the main difference for clients when sending a request to a resource server?

After receiving the 'grant', the client has to create a JWT-based access_token. This 'grant' has to be part of the access_tokens payload. When signing the JWT, the client has to use a private key 'that matches' the registered public key or the one identified via 'kid'. The goal is to provide a way for the client to proof to the resource server that it is the correct entity who received the grant. It enables the resource server also to accept a client's public key which would not be accepted otherwise (i.e.: self-signed).

Clients may use the same grant multiple times. As long as the required SCOPE does not change and the 'max_age' of the grant has not passed 'it is good to go'. Nevertheless, the resource server should check regularly if the given grant (consent) is still active!

Content of the 'access_token':

What is the main difference for resource servers?

If the resource server leverages the authorization servers /introspection endpoint, more or less nothing changes. That endpoint will return details that can be used for validation purposes. But, if the resource server wants to validate the access_token locally, it has to run JWT-based validations:

  1. decode the JWT-based access_token
  2. extract and decode 'grant'
  3. validate the 'grant' (iss, nbf, max_age, signature)
  4. extract 'grant.scope' and check if it meets local requirements
  5. extract 'grant.target' and check if it is meant for this resource. To be ignored if empty

If the first validation was successful the resource owner can now check if the provided grant was actually made for this client:

  1. compare: access_token.jwt-header.alg == grant.aud_alg
  2. compare: base64url(S256(access_token.jwt-header.x5c)) == grant.cnf.x5t#S256
  3. validate the access_token (max_age, signature)

What are known threats that may be mitigated using this solution?

This list gives just an indication of what is preventable:

  1. code interception attack: this is mitigated by providing a proof-of-possession check. Unless a client has 'lost' his private key (or potentially a shared secret) this should not be possible. See RFC 7636 for more details on how its being prevented today
  2. oauth mix up attack: this is mitigated by not requiring a seconds api call (/token endpoint). See OAuth 2.0 Mix-Up Mitigation for more details
  3. access_token data leaks: no token are stored at a central location and therefore they cannot be 'lost' or 'stolen'

What about existing grant_types, can they be supported?

Overall, my gut tells me that not all existing grant_types are still needed. But this has to be evaluated a little later.

How could this be started?

I think that most OpenID Connect providers already have a lot of required implementations in place. For example, clients can already register with jwks_uri's. In addition, adding a new response_type should be simpler than modifying existing ones. Overall response_type=grant should be similar to response_type=code, at least up to the point where the code (grant) gets issued.

Persisting the introduced grantId should be small effort, at least for any implementation that already manages given 'consent' decisions without leveraging issued token.

For resource servers, they need to support JWT which they may already do today. In addition, it may be useful to change the type of token definition. If resource servers support bearer token, jwt-based access_token and now client-issued-jwt-access_token, there should be an indicator. For example, something like:
Authorization: Grant {token} instead of Authorization: Bearer {token}

Links

I took the name 'cnf.x5t#S256' from here, to not introduce yet another term for the same thing!

Feedback

I hope this post is at least good enough to start a discussion on this topic.

My web site currently does not support any kind of discussion forum, so please send me an email or contact me via twitter. Contact.

Financial API (FAPI)
10. April 2017

The Financial API (FAPI) Working Group (WG) was founded within the OpenID Foundation only a few months ago. The goal of the group is to develop OAuth and OpenID Connect based APIs for the financial industry. The specification is divided into different types of APIs to support "read only" and "write" operations. The first draft of the security profile for "read only" APIs has been finalized a few weeks ago and is available here.

FAPI is extremely valuable for anybody who has to support PSD2 (find more info about PSD2 here) since it specifies a common API interface. If you want to get involved in this exciting WG (like myself) sign up for the mailing list! This link is your starting point to get onto the mailing list and to learn more about FAPI in general.

First blogs are registered!
02. February 2017

I am happy to announce that the first bloggers have registered a reference to their own blog!
API-University and API Academy.

oauth.blog is active!
31. January 2017

This website is now active. But currently I am still testing it. Therefore it says Still under development!. Please feel free to come back in the next few days to browse blogs that are relevant in the context of OAuth, OpenID Connect or otherwise identity and security related.

oauth.blog
04. January 2017

Currently I am working on the content for oauth.blog. My goal is to provide an easy flow for anyone who wants to display a reference to his own blog that is oauth related. As you may see I am not an HTML expert, I am a server guy, building these pages takes time ... .

The content for apisecurity.info, apisecurity.blog and nascarlogin.com has to wait. The 'Sign Up' and 'Login' buttons at the top right corner will be enabled as soon as I am done with the server side, the non-visual parts.

For the time being, please feel free to send me an email or a message on Twitter as mentioned below.

nascarlogin.com, oauth.blog and apisecurity.blog

If you used one of those addresses above and ended up here, you are at the right location.

I am in the process of rebuilding this page.

If you came here to play with social login (the nascarlogin.com part of this website) to find out what information providers return to clients, when you use social login, please come back later.

If you came here to read blogs about oauth or api security, please come back later too.

I know there are many blogs for those topics out there. To make every one's life easier I would like this page to become some kind of collective starting point for interested people.

I am trying to get this page going until the end of December 2016.

If you are interested in publishing or referencing a related blog here please let me know via Twitter or email.

If you came here to find out what oauth is, start with the RFC 6749.

If you came here to find out what OpenID Connect is, start with the CORE part of it.

For information about api security, here is an overview provided by OWASP REST Security Cheat Sheet.

My own oauth related blog can be found here, although it is heavily related to the product I work on in my professional life.