- Access token generation
- Access token transportation
- Access token verification
- Service registration
- Key discovery
This document describes ASAP (Atlassian S2S Authentication Protocol), a mechanism used by a resource server to authenticate requests from the client in a client-server communication scenario between software services.
Where possible, this document borrows from the terminology introduced by OAuth 2.0 and JWT. The following terms are used:
- Service: a software entity that participates in the communication. A service can adopt various roles (see below).
- Client (role): as in OAuth 2.0 (RFC6749).
- Resource server (role): as in OAuth 2.0 (RFC6749).
- Access token (object): as in OAuth 2.0 (RFC6749).
- Bearer token (object): as in OAuth 2.0 (RFC6750).
- Request (object): a message from the client to the resource server, as in HTTP (RFC7230).
Scope and goals
The primary goal is to allow the resource server to be confident that an incoming request comes from an authentic, identifiable client. Other goals are:
- Performance: minimise the overhead of the protocol, especially the number of requests.
- Avoid secret distribution.
This specification only addresses request authentication. The following is not covered here:
- Server authentication. Use TLS 1.2 with PFS for this.
- Private channel. Use TLS 1.2 for PFS for this.
- Authorisation. The resource server is free to implement authorisation.
- Access delegation. This specification is not relevant in that scenario; consider OAuth instead.
- Browser to service communication.
- Service discovery. It is assumed that the client knows the location (URL) of the resource server at development time or configuration time.
At this stage, it is assumed that authentic services (clients and resource servers) can be trusted.
Please see the repository version history of this page for details.
This is an unnumbered draft version.
An authentic request is defined as a request that has been generated by an identifiable client in a particular context within a given timeframe.
This protocol enables the resource server to decide the authenticity of an incoming request based on the information contained in an access token that is include with the request. The access token is:
- Self-issued by the client. The client does not need to collaborate with any other entity to generate the token.
- Signed to ensure its integrity.
- Verifiable. The resource server can verify the author of the token without collaborating with any other entity, assuming that it already has, or can discover, the public key of the client.
- A bearer token. A valid token is enough evidence to authenticate an incoming request. No proof-of-possession is required.
As a consequence of the properties above, if an access token is leaked, it cannot be revoked. To balance this weakness, access tokens are very specific so they cannot be used in different context, and they are short-lived.
+---------+ +-----------------+ +-----------------+ | Client | | Resource_Server | | Key_Repository | +---------+ +-----------------+ +-----------------+ | | | | | | | Issue signed access token | | |-------------------------- | | | | | | |<------------------------- | | | | | | | | | Send request with access token | | |---------------------------------------->| | | | | | | | | | [unknown key] | | | Fetch key | | |------------------------------------->| | | | | | | | | Verify claims and signature | | |---------------------------- | | | | | | |<--------------------------- | | | | | | | | return resource | | |<----------------------------------------| | | | |
The access token is a String that the client includes with each request that it makes to the resource provider.
The token format MUST be signed JWT. Tokens MUST be signed with the private key of the client using JWS.
The JOSE header (the first component of the JWT triple) MUST contain at least:
- “alg”: the algorithm used to sign the token. It MUST be one of the asymmetric key algorithms defined by JWA. It MUST NOT be ‘none’, and it MUST NOT be a symmetric key algorithm.
- “kid”: key identifier, as defined by JWS, with the difference that here it is mandatory. The key identifier MUST be a String that is a non-empty sequence of non-empty substrings joined with the forward slash character (“/”). None of the substrings can be “.” or “..”. As a further restriction, the key identifier must match the following Java regular expression:
The JOSE header MAY contain the “typ” header, but since JWS is being used, this header MUST be ignored.
The claims of the JWT token MUST contain:
- “iss”: issuer, as defined by JWT, with the difference that here it is mandatory and that the value must be a String (not a StringOrURI). This String identifies the service that issues the token. To eliminate the risk of collisions and ensure key discoverability, service identifiers MUST be registered (see Service Registration).
- “exp”: token expiry timestamp, as defined by JWT, with the difference that here it is mandatory.
- “iat”: issued at time, as defined by JWT, with the difference that here it is mandatory.
- “aud”: audience, as defined by JWT, with the difference that here it is mandatory. Note that the value of this claim may be a single string value or an array of string values.
- “jti”: token identifier, defined by JWT, with the difference that here it is mandatory.
The claims of the JWT token MAY contain:
- “sub”: subject, as defined by JWT. This String identifies the principal (service or individual). If absent, the receiver MUST assume that the token was self-issued and therefore the subject is the same as the issuer.
- “nbf”: not before, as defined by JWT.
Access token generation
In this version, the access tokens are issued by the client, who assumes the role of the issuer and decides the subject. As an issuer, it owns one or more private keys.
To generate an access token, the issuer MUST follow the instructions defined by JWT and JWS and sign it with one of the private keys owned by the issuer. Since all resource servers MUST implement at least RS256 (as defined by JWA), the client SHOULD use RS256 to ensure interoperability with the resource server.
On top of those instructions, to generate the access token the issuer MUST, at least:
- Set the “iss” claim with the service identifier of the client.
- Set the “iat” claim to the current time according to its internal clock.
- Set the “exp” claim to a time in the future (“exp” MUST be after “iat”). For security reasons, the client SHOULD issue short-lived tokens. If the environment can guarantee a good synchronisation between the internal clocks of the systems involved in the communication, a sub-minute expire time is recommended. There is a hard limit of one hour.
- Set the “kid” header to the identifier of the key used to sign the token. The value of “kid” MUST be prefixed with the service identifier of the client and a “/” character.
- Set the “aud” claim to a value that identifies the resource server. The issuer and the resource server have to mutually agree on this identifier. The details of how they reach agreement are not covered in this version of the specification.
- Set the “jti” claim to a generated nonce value that is unique within the temporal window of the token life time. The client MUST ensure that there is a very low probability that at any point in time there are more than one valid and non-expired tokens with the same “jti” value, considering that there may be many issuers and many instances of the same issuer.
For a successful communication, the resource server needs to know the public key identified by “kid”. Therefore the client SHOULD make sure that the public key identified by “kid” is available in the key repository, see “Key discovery” below.
The client MAY reuse the same token for multiple HTTP requests to the resource server within the lifetime of the token except if the resource server explicitly documented that it enforces a token single use policy.
Access token transportation
The client MUST include the access token with all the requests made to the resource server. Although RFC6750 defines multiple transportation methods, this specification only supports one of them: the “Authorization” HTTP header with the “Bearer” authentication scheme. That means that the “access_token” parameter in the request-body and the “access_token” query parameter in the URI are not supported.
The access token MUST be serialised using the JWS Compact Serialisation format, as defined by JWS.
Access token verification
The resource server MUST decode and verify the signature of the access token using the public key of the issuer (“iss”) identified by “kid”. Detailed instructions to decode and verify the access token are given by JWT and JWS. Resource servers MUST implement at least the RS256 algorithm (as defined by JWA), and they CAN implement other algorithms. Resource servers MUST reject tokens signed with an unsupported algorithm.
The resource server MUST ignore the following claims if they are present in the header of the access token:
- “jku”: as defined by JWS.
- “jwk”: as defined by JWS.
- “x5u”: as defined by JWS.
- “x5c”: as defined by JWS.
- “x5t”: as defined by JWS.
- “x5t#S256”: as defined by JWS.
The resource server needs the public key in order to verify the access token signature. Either the key it is known statically (by configuration) or it can be discovered at runtime (see Key discovery). The claimed key is identified by the “kid”. Invalid signatures, signatures made with an unknown key, and signatures made with a key different from the claimed one MUST be rejected. Unsigned access tokens MUST be rejected.
The resource server MUST check that the key identified by “kid” is owned by the issuer. In order to do so, the resource server MAY check if the “kid” string starts with “$iss/” (where $iss is the value of the “iss” claim) and, in affirmative case, accept that as proof of ownership of the key by the issuer. The resource server MAY use other mechanisms to the same effect.
If the “sub” claim is not defined, the resource server MUST assume that the effective subject is the same as the issuer.
The resource server MUST verify that it is the intended audience of the access token by checking that at least one of the values of “aud” is the identifier of the resource server mutually agreed by the client and the resource server. The details of how they reach agreement are not covered in this version of the specification.
The resource server MAY reject a token if the token nonce (“jti”) has been previously seen by the resource server in another request. If the resource server decides to implement duplicate detection, it MUST explicitly document that behaviour.
The resource server MUST verify that the current time is between “nbf” (optional) and “exp” (required), inclusive. For the purposes of this comparison, a missing “nbf” claim defaults to the value of “iat”. The resource server MAY offer, at its discretion, a grace period to compensate for internal clock divergences between the client and the resource server.
The resource server MUST reject a token if it lifespan (the difference between “exp” and “iat”) exceeds one hour (hard limit). A resource server MAY implement, at its discretion, a more restrictive upper bound for the lifespan of a token.
Besides the values of “kid”, “iss”, “sub”, “nbf”, “exp” and the signature, the resource server MUST NOT use any other claim or header as the basis to decide if the request is authentic.
If the resource server successfully verifies and accepts the access token, then it MUST process the request and it MUST assume that the request was issued by the issuer. If the resource server rejects the access token, then it MUST reply with a status code of 401 UNAUTHORIZED and MUST include a WWW-Authenticate header field as per the HTTP specification. If the resource server receives a request for a resource that is not available anonymously and the request does not include an access token, then it MUST reply with a status code of 401 UNAUTHORIZED and MUST include a WWW-Authenticate header field as per the HTTP specification.
The verification process described in this section allows the resource server to authenticate the token as a valid token issued by the owner of the private key. This process does not cover the following aspects that the resource server SHOULD implement by its own means:
- The resource server MAY decide if the verified issuer is authorised to communicate with the resource server.
- The resource server MAY decide if the verified issuer is authorised to make requests in relation to the claimed subject (principal).
- The resource server MAY decide if the combination of verified issuer and effective subject is authorised to make the requested business operation.
Services are univocally identified by a String, which MUST be a String with the same restrictions described above for the key identifier.
A centralised unique service registry MUST be maintained by an authority to avoid identifier clashes. The details of how to implement that are out of scope of this document.
Part of the service registration process MAY involve generating a priv/pub key pair and uploading the public key to the key repository to enable key discovery.
When the resource server receives a request, it needs the public key to verify the signature of the access token. If the resource server does not know the public key of the claimed issuer, it MAY use the following key discovery process to obtain it.
The key discovery is performed by retrieving a resource in PEM format (RFC1422) from a key repository identified by a base URL. The base URL of the key repository MUST be statically known to the resource server. The relative URL path is a function of the key identifier (“kid”), as follows:
The key repository MAY be a web server that exposes the keys via unauthenticated HTTPS. In that case, the base URL MUST start with “https:”. The resource server MUST send a GET request and it SHOULD include an “Accept” header that expresses preference for the MIME type “application/x-pem-file”. It also MUST follow HTTP redirects. The key repository SHOULD serve the resource with “Content-Type: application/x-pem-file”. The resource server MAY use HTTP caching to store a cached copy of the public key. As per the HTTP caching protocol, failures to retrieve a key MUST NOT be cached.
Public keys published in the key repository NEVER change, but MAY be eventually removed. The resource server SHOULD NOT implement any other caching mechanism than HTTP caching, as it hinders the propagation of deletion of a compromised key.
The resource server trusts the keys obtained by following redirections from the original HTTP request. Therefore, key repositories MUST ensure that all the contents in the key repository or reachable by redirections from the key repository are trustworthy. For security reasons, a key repository SHOULD serve only static files and SHOULD avoid open redirections.
- RFC1422: Privacy Enhancement for Internet Electronic Mail: Part II: Certificate-Based Key Management (February 1993): https://tools.ietf.org/html/rfc1422
- RFC3986: Uniform Resource Identifier (URI): Generic Syntax (January 2005): http://www.ietf.org/rfc/rfc3986.txt
- RFC6749: OAuth 2.0 (October 2012): http://tools.ietf.org/html/rfc6749
- RFC6750: The OAuth 2.0 Authorization Framework: Bearer Token Usage (October 2012): https://tools.ietf.org/html/rfc6750
- RFC7230: Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing:https://tools.ietf.org/html/rfc7230
- RFC7235: Hypertext Transfer Protocol (HTTP/1.1): Authentication: http://tools.ietf.org/html/rfc7235
- RFC7515: JSON Web Signature (JWS): https://tools.ietf.org/html/rfc7515
- RFC7518: JSON Web Algorithms (JWA): https://tools.ietf.org/html/rfc7518
- RFC7519: JSON Web Token (JWT): https://tools.ietf.org/html/rfc7519