426 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			Markdown
		
	
	
			
		
		
	
	
			426 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			Markdown
		
	
	
<!--[metadata]>
 | 
						|
+++
 | 
						|
title = "Docker Registry v2 Authentication"
 | 
						|
description = "Introduces the Docker Registry v2 authentication"
 | 
						|
keywords = ["registry, images, repository, v2,  authentication"]
 | 
						|
[menu.main]
 | 
						|
parent="smn_registry_ref"
 | 
						|
+++
 | 
						|
<![end-metadata]-->
 | 
						|
 | 
						|
 | 
						|
 | 
						|
# Docker Registry v2 authentication via central service
 | 
						|
 | 
						|
Today a Docker Registry can run in standalone mode in which there are no
 | 
						|
authorization checks. While adding your own HTTP authorization requirements in
 | 
						|
a proxy placed between the client and the registry can give you greater access
 | 
						|
control, we'd like a native authorization mechanism that's public key based
 | 
						|
with access control lists managed separately with the ability to have fine
 | 
						|
granularity in access control on a by-key, by-user, by-namespace, and
 | 
						|
by-repository basis. In v1 this can be configured by specifying an
 | 
						|
`index_endpoint` in the registry's config. Clients present tokens generated by
 | 
						|
the index and tokens are validated on-line by the registry with every request.
 | 
						|
This results in a complex authentication and authorization loop that occurs
 | 
						|
with every registry operation. Some people are very familiar with this image:
 | 
						|
 | 
						|

 | 
						|
 | 
						|
The above image outlines the 6-step process in accessing the Official Docker
 | 
						|
Registry.
 | 
						|
 | 
						|
1. Contact the Docker Hub to know where I should download “samalba/busybox”
 | 
						|
2. Docker Hub replies:
 | 
						|
    a. samalba/busybox is on Registry A
 | 
						|
    b. here are the checksums for samalba/busybox (for all layers)
 | 
						|
    c. token
 | 
						|
3. Contact Registry A to receive the layers for samalba/busybox (all of them to
 | 
						|
   the base image). Registry A is authoritative for “samalba/busybox” but keeps
 | 
						|
   a copy of all inherited layers and serve them all from the same location.
 | 
						|
4. Registry contacts Docker Hub to verify if token/user is allowed to download
 | 
						|
   images.
 | 
						|
5. Docker Hub returns true/false lettings registry know if it should proceed or
 | 
						|
   error out.
 | 
						|
6. Get the payload for all layers.
 | 
						|
 | 
						|
The goal of this document is to outline a way to eliminate steps 4 and 5 from
 | 
						|
the above process by using cryptographically signed tokens and no longer
 | 
						|
require the client to authenticate each request with a username and password
 | 
						|
stored locally in plain text.
 | 
						|
 | 
						|
The new registry workflow is more like this:
 | 
						|
 | 
						|

 | 
						|
 | 
						|
1. Attempt to begin a push/pull operation with the registry.
 | 
						|
2. If the registry requires authorization it will return a `401 Unauthorized`
 | 
						|
   HTTP response with information on how to authenticate.
 | 
						|
3. The registry client makes a request to the authorization service for a
 | 
						|
   signed JSON Web Token.
 | 
						|
4. The authorization service returns a token.
 | 
						|
5. The client retries the original request with the token embedded in the
 | 
						|
   request header.
 | 
						|
6. The Registry authorizes the client and begins the push/pull session as
 | 
						|
   usual. 
 | 
						|
 | 
						|
## Requirements
 | 
						|
 | 
						|
- Registry Clients capable of generating key pairs which can be used to
 | 
						|
  authenticate to an authorization server.
 | 
						|
- An authorization server capable of managing user accounts, their public keys,
 | 
						|
  and access controls to their resources hosted by any given service (such as
 | 
						|
  repositories in a Docker Registry).
 | 
						|
- A Docker Registry capable of trusting the authorization server to sign tokens
 | 
						|
  which clients can use for authorization and the ability to verify these
 | 
						|
  tokens for single use or for use during a sufficiently short period of time.
 | 
						|
 | 
						|
## Authorization Server Endpoint Descriptions
 | 
						|
 | 
						|
This document borrows heavily from the [JSON Web Token Draft Spec](https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-32)
 | 
						|
 | 
						|
The described server is meant to serve as a user account and key manager and a
 | 
						|
centralized access control list for resources hosted by other services which
 | 
						|
wish to authenticate and manage authorizations using this services accounts and
 | 
						|
their public keys.
 | 
						|
 | 
						|
Such a service could be used by the official docker registry to authenticate
 | 
						|
clients and verify their authorization to docker image repositories.
 | 
						|
 | 
						|
Docker will need to be updated to interact with an authorization server to get
 | 
						|
an authorization token.
 | 
						|
 | 
						|
## How to authenticate
 | 
						|
 | 
						|
Today, registry clients first contact the index to initiate a push or pull.
 | 
						|
For v2, clients should contact the registry first. If the registry server
 | 
						|
requires authentication it will return a `401 Unauthorized` response with a
 | 
						|
`WWW-Authenticate` header detailing how to authenticate to this registry.
 | 
						|
 | 
						|
For example, say I (username `jlhawn`) am attempting to push an image to the
 | 
						|
repository `samalba/my-app`. For the registry to authorize this, I either need
 | 
						|
`push` access to the `samalba/my-app` repository or `push` access to the whole
 | 
						|
`samalba` namespace in general. The registry will first return this response:
 | 
						|
 | 
						|
```
 | 
						|
HTTP/1.1 401 Unauthorized
 | 
						|
WWW-Authenticate: Bearer realm="https://auth.docker.com/v2/token/",service="registry.docker.com",scope="repository:samalba/my-app:push"
 | 
						|
```
 | 
						|
 | 
						|
This format is documented in [Section 3 of RFC 6750: The OAuth 2.0 Authorization Framework: Bearer Token Usage](https://tools.ietf.org/html/rfc6750#section-3)
 | 
						|
 | 
						|
The client will then know to make a `GET` request to the URL
 | 
						|
`https://auth.docker.com/v2/token/` using the `service` and `scope` values from
 | 
						|
the `WWW-Authenticate` header.
 | 
						|
 | 
						|
## Requesting a Token
 | 
						|
 | 
						|
#### Query Parameters
 | 
						|
 | 
						|
<dl>
 | 
						|
    <dt>
 | 
						|
        <code>service</code>
 | 
						|
    </dt>
 | 
						|
    <dd>
 | 
						|
        The name of the service which hosts the resource.
 | 
						|
    </dd>
 | 
						|
    <dt>
 | 
						|
        <code>scope</code>
 | 
						|
    </dt>
 | 
						|
    <dd>
 | 
						|
        The resource in question, formatted as one of the space-delimited
 | 
						|
        entries from the <code>scope</code> parameters from the <code>WWW-Authenticate</code> header
 | 
						|
        shown above. This query parameter should be specified multiple times if
 | 
						|
        there is more than one <code>scope</code> entry from the <code>WWW-Authenticate</code>
 | 
						|
        header. The above example would be specified as:
 | 
						|
        <code>scope=repository:samalba/my-app:push</code>.
 | 
						|
    </dd>
 | 
						|
    <dt>
 | 
						|
        <code>account</code>
 | 
						|
    </dt>
 | 
						|
    <dd>
 | 
						|
        The name of the account which the client is acting as. Optional if it
 | 
						|
        can be inferred from client authentication.
 | 
						|
    </dd>
 | 
						|
</dl>
 | 
						|
 | 
						|
#### Description
 | 
						|
 | 
						|
Requests an authorization token for access to a specific resource hosted by a
 | 
						|
specific service provider. Requires the client to authenticate either using a
 | 
						|
TLS client certificate or using basic authentication (or any other kind of
 | 
						|
digest/challenge/response authentication scheme if the client doesn't support
 | 
						|
TLS client certs). If the key in the client certificate is linked to an account
 | 
						|
then the token is issued for that account key. If the key in the certificate is
 | 
						|
linked to multiple accounts then the client must specify the `account` query
 | 
						|
parameter. The returned token is in JWT (JSON Web Token) format, signed using
 | 
						|
the authorization server's private key.
 | 
						|
 | 
						|
#### Example
 | 
						|
 | 
						|
For this example, the client makes an HTTP request to the following endpoint
 | 
						|
over TLS using a client certificate with the server being configured to allow a
 | 
						|
non-verified issuer during the handshake (i.e., a self-signed client cert is
 | 
						|
okay).
 | 
						|
 | 
						|
```
 | 
						|
GET /v2/token/?service=registry.docker.com&scope=repository:samalba/my-app:push&account=jlhawn HTTP/1.1
 | 
						|
Host: auth.docker.com
 | 
						|
```
 | 
						|
 | 
						|
The server first inspects the client certificate to extract the subject key and
 | 
						|
lookup which account it is associated with. The client is now authenticated
 | 
						|
using that account.
 | 
						|
 | 
						|
The server next searches its access control list for the account's access to
 | 
						|
the repository `samalba/my-app` hosted by the service `registry.docker.com`.
 | 
						|
 | 
						|
The server will now construct a JSON Web Token to sign and return. A JSON Web
 | 
						|
Token has 3 main parts:
 | 
						|
 | 
						|
1.  Headers
 | 
						|
 | 
						|
    The header of a JSON Web Token is a standard JOSE header. The "typ" field
 | 
						|
    will be "JWT" and it will also contain the "alg" which identifies the
 | 
						|
    signing algorithm used to produce the signature. It will also usually have
 | 
						|
    a "kid" field, the ID of the key which was used to sign the token.
 | 
						|
 | 
						|
    Here is an example JOSE Header for a JSON Web Token (formatted with
 | 
						|
    whitespace for readability):
 | 
						|
 | 
						|
    ```
 | 
						|
    {
 | 
						|
        "typ": "JWT",
 | 
						|
        "alg": "ES256",
 | 
						|
        "kid": "PYYO:TEWU:V7JH:26JV:AQTZ:LJC3:SXVJ:XGHA:34F2:2LAQ:ZRMK:Z7Q6"
 | 
						|
    }
 | 
						|
    ```
 | 
						|
 | 
						|
    It specifies that this object is going to be a JSON Web token signed using
 | 
						|
    the key with the given ID using the Elliptic Curve signature algorithm
 | 
						|
    using a SHA256 hash.
 | 
						|
 | 
						|
2.  Claim Set
 | 
						|
 | 
						|
    The Claim Set is a JSON struct containing these standard registered claim
 | 
						|
    name fields:
 | 
						|
 | 
						|
    <dl>
 | 
						|
        <dt>
 | 
						|
            <code>iss</code> (Issuer)
 | 
						|
        </dt>
 | 
						|
        <dd>
 | 
						|
            The issuer of the token, typically the fqdn of the authorization
 | 
						|
            server.
 | 
						|
        </dd>
 | 
						|
        <dt>
 | 
						|
            <code>sub</code> (Subject)
 | 
						|
        </dt>
 | 
						|
        <dd>
 | 
						|
            The subject of the token; the id of the client which requested it.
 | 
						|
        </dd>
 | 
						|
        <dt>
 | 
						|
            <code>aud</code> (Audience)
 | 
						|
        </dt>
 | 
						|
        <dd>
 | 
						|
            The intended audience of the token; the id of the service which
 | 
						|
            will verify the token to authorize the client/subject.
 | 
						|
        </dd>
 | 
						|
        <dt>
 | 
						|
            <code>exp</code> (Expiration)
 | 
						|
        </dt>
 | 
						|
        <dd>
 | 
						|
            The token should only be considered valid up to this specified date
 | 
						|
            and time.
 | 
						|
        </dd>
 | 
						|
        <dt>
 | 
						|
            <code>nbf</code> (Not Before)
 | 
						|
        </dt>
 | 
						|
        <dd>
 | 
						|
            The token should not be considered valid before this specified date
 | 
						|
            and time.
 | 
						|
        </dd>
 | 
						|
        <dt>
 | 
						|
            <code>iat</code> (Issued At)
 | 
						|
        </dt>
 | 
						|
        <dd>
 | 
						|
            Specifies the date and time which the Authorization server
 | 
						|
            generated this token.
 | 
						|
        </dd>
 | 
						|
        <dt>
 | 
						|
            <code>jti</code> (JWT ID)
 | 
						|
        </dt>
 | 
						|
        <dd>
 | 
						|
            A unique identifier for this token. Can be used by the intended
 | 
						|
            audience to prevent replays of the token.
 | 
						|
        </dd>
 | 
						|
    </dl>
 | 
						|
 | 
						|
    The Claim Set will also contain a private claim name unique to this
 | 
						|
    authorization server specification:
 | 
						|
 | 
						|
    <dl>
 | 
						|
        <dt>
 | 
						|
            <code>access</code>
 | 
						|
        </dt>
 | 
						|
        <dd>
 | 
						|
            An array of access entry objects with the following fields:
 | 
						|
 | 
						|
            <dl>
 | 
						|
                <dt>
 | 
						|
                    <code>type</code>
 | 
						|
                </dt>
 | 
						|
                <dd>
 | 
						|
                    The type of resource hosted by the service.
 | 
						|
                </dd>
 | 
						|
                <dt>
 | 
						|
                    <code>name</code>
 | 
						|
                </dt>
 | 
						|
                <dd>
 | 
						|
                    The name of the resource of the given type hosted by the
 | 
						|
                    service.
 | 
						|
                </dd>
 | 
						|
                <dt>
 | 
						|
                    <code>actions</code>
 | 
						|
                </dt>
 | 
						|
                <dd>
 | 
						|
                    An array of strings which give the actions authorized on
 | 
						|
                    this resource.
 | 
						|
                </dd>
 | 
						|
            </dl>
 | 
						|
        </dd>
 | 
						|
    </dl>
 | 
						|
 | 
						|
    Here is an example of such a JWT Claim Set (formatted with whitespace for
 | 
						|
    readability):
 | 
						|
 | 
						|
    ```
 | 
						|
    {
 | 
						|
        "iss": "auth.docker.com",
 | 
						|
        "sub": "jlhawn",
 | 
						|
        "aud": "registry.docker.com",
 | 
						|
        "exp": 1415387315,
 | 
						|
        "nbf": 1415387015,
 | 
						|
        "iat": 1415387015,
 | 
						|
        "jti": "tYJCO1c6cnyy7kAn0c7rKPgbV1H1bFws",
 | 
						|
        "access": [
 | 
						|
            {
 | 
						|
                "type": "repository",
 | 
						|
                "name": "samalba/my-app",
 | 
						|
                "actions": [
 | 
						|
                    "push"
 | 
						|
                ]
 | 
						|
            }
 | 
						|
        ]
 | 
						|
    }
 | 
						|
    ```
 | 
						|
 | 
						|
3.  Signature
 | 
						|
 | 
						|
    The authorization server will produce a JOSE header and Claim Set with no
 | 
						|
    extraneous whitespace, i.e., the JOSE Header from above would be
 | 
						|
 | 
						|
    ```
 | 
						|
    {"typ":"JWT","alg":"ES256","kid":"PYYO:TEWU:V7JH:26JV:AQTZ:LJC3:SXVJ:XGHA:34F2:2LAQ:ZRMK:Z7Q6"}
 | 
						|
    ```
 | 
						|
 | 
						|
    and the Claim Set from above would be
 | 
						|
 | 
						|
    ```
 | 
						|
    {"iss":"auth.docker.com","sub":"jlhawn","aud":"registry.docker.com","exp":1415387315,"nbf":1415387015,"iat":1415387015,"jti":"tYJCO1c6cnyy7kAn0c7rKPgbV1H1bFws","access":[{"type":"repository","name":"samalba/my-app","actions":["push"]}]}
 | 
						|
    ```
 | 
						|
 | 
						|
    The utf-8 representation of this JOSE header and Claim Set are then
 | 
						|
    url-safe base64 encoded (sans trailing '=' buffer), producing:
 | 
						|
 | 
						|
    ```
 | 
						|
    eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiIsImtpZCI6IlBZWU86VEVXVTpWN0pIOjI2SlY6QVFUWjpMSkMzOlNYVko6WEdIQTozNEYyOjJMQVE6WlJNSzpaN1E2In0
 | 
						|
    ```
 | 
						|
 | 
						|
    for the JOSE Header and
 | 
						|
 | 
						|
    ```
 | 
						|
    eyJpc3MiOiJhdXRoLmRvY2tlci5jb20iLCJzdWIiOiJqbGhhd24iLCJhdWQiOiJyZWdpc3RyeS5kb2NrZXIuY29tIiwiZXhwIjoxNDE1Mzg3MzE1LCJuYmYiOjE0MTUzODcwMTUsImlhdCI6MTQxNTM4NzAxNSwianRpIjoidFlKQ08xYzZjbnl5N2tBbjBjN3JLUGdiVjFIMWJGd3MiLCJhY2Nlc3MiOlt7InR5cGUiOiJyZXBvc2l0b3J5IiwibmFtZSI6InNhbWFsYmEvbXktYXBwIiwiYWN0aW9ucyI6WyJwdXNoIl19XX0
 | 
						|
    ```
 | 
						|
 | 
						|
    for the Claim Set. These two are concatenated using a '.' character,
 | 
						|
    yielding the string:
 | 
						|
 | 
						|
    ```
 | 
						|
    eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiIsImtpZCI6IlBZWU86VEVXVTpWN0pIOjI2SlY6QVFUWjpMSkMzOlNYVko6WEdIQTozNEYyOjJMQVE6WlJNSzpaN1E2In0.eyJpc3MiOiJhdXRoLmRvY2tlci5jb20iLCJzdWIiOiJqbGhhd24iLCJhdWQiOiJyZWdpc3RyeS5kb2NrZXIuY29tIiwiZXhwIjoxNDE1Mzg3MzE1LCJuYmYiOjE0MTUzODcwMTUsImlhdCI6MTQxNTM4NzAxNSwianRpIjoidFlKQ08xYzZjbnl5N2tBbjBjN3JLUGdiVjFIMWJGd3MiLCJhY2Nlc3MiOlt7InR5cGUiOiJyZXBvc2l0b3J5IiwibmFtZSI6InNhbWFsYmEvbXktYXBwIiwiYWN0aW9ucyI6WyJwdXNoIl19XX0
 | 
						|
    ```
 | 
						|
 | 
						|
    This is then used as the payload to a the `ES256` signature algorithm
 | 
						|
    specified in the JOSE header and specified fully in [Section 3.4 of the JSON Web Algorithms (JWA)
 | 
						|
    draft specification](https://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-38#section-3.4)
 | 
						|
 | 
						|
    This example signature will use the following ECDSA key for the server:
 | 
						|
 | 
						|
    ```
 | 
						|
    {
 | 
						|
        "kty": "EC",
 | 
						|
        "crv": "P-256",
 | 
						|
        "kid": "PYYO:TEWU:V7JH:26JV:AQTZ:LJC3:SXVJ:XGHA:34F2:2LAQ:ZRMK:Z7Q6",
 | 
						|
        "d": "R7OnbfMaD5J2jl7GeE8ESo7CnHSBm_1N2k9IXYFrKJA",
 | 
						|
        "x": "m7zUpx3b-zmVE5cymSs64POG9QcyEpJaYCD82-549_Q",
 | 
						|
        "y": "dU3biz8sZ_8GPB-odm8Wxz3lNDr1xcAQQPQaOcr1fmc"
 | 
						|
    }
 | 
						|
    ```
 | 
						|
 | 
						|
    A resulting signature of the above payload using this key is:
 | 
						|
 | 
						|
    ```
 | 
						|
    QhflHPfbd6eVF4lM9bwYpFZIV0PfikbyXuLx959ykRTBpe3CYnzs6YBK8FToVb5R47920PVLrh8zuLzdCr9t3w
 | 
						|
    ```
 | 
						|
 | 
						|
    Concatenating all of these together with a `.` character gives the
 | 
						|
    resulting JWT:
 | 
						|
 | 
						|
    ```
 | 
						|
    eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiIsImtpZCI6IlBZWU86VEVXVTpWN0pIOjI2SlY6QVFUWjpMSkMzOlNYVko6WEdIQTozNEYyOjJMQVE6WlJNSzpaN1E2In0.eyJpc3MiOiJhdXRoLmRvY2tlci5jb20iLCJzdWIiOiJqbGhhd24iLCJhdWQiOiJyZWdpc3RyeS5kb2NrZXIuY29tIiwiZXhwIjoxNDE1Mzg3MzE1LCJuYmYiOjE0MTUzODcwMTUsImlhdCI6MTQxNTM4NzAxNSwianRpIjoidFlKQ08xYzZjbnl5N2tBbjBjN3JLUGdiVjFIMWJGd3MiLCJhY2Nlc3MiOlt7InR5cGUiOiJyZXBvc2l0b3J5IiwibmFtZSI6InNhbWFsYmEvbXktYXBwIiwiYWN0aW9ucyI6WyJwdXNoIl19XX0.QhflHPfbd6eVF4lM9bwYpFZIV0PfikbyXuLx959ykRTBpe3CYnzs6YBK8FToVb5R47920PVLrh8zuLzdCr9t3w
 | 
						|
    ```
 | 
						|
 | 
						|
This can now be placed in an HTTP response and returned to the client to use to
 | 
						|
authenticate to the audience service:
 | 
						|
 | 
						|
 | 
						|
```
 | 
						|
HTTP/1.1 200 OK
 | 
						|
Content-Type: application/json
 | 
						|
 | 
						|
{"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiIsImtpZCI6IlBZWU86VEVXVTpWN0pIOjI2SlY6QVFUWjpMSkMzOlNYVko6WEdIQTozNEYyOjJMQVE6WlJNSzpaN1E2In0.eyJpc3MiOiJhdXRoLmRvY2tlci5jb20iLCJzdWIiOiJqbGhhd24iLCJhdWQiOiJyZWdpc3RyeS5kb2NrZXIuY29tIiwiZXhwIjoxNDE1Mzg3MzE1LCJuYmYiOjE0MTUzODcwMTUsImlhdCI6MTQxNTM4NzAxNSwianRpIjoidFlKQ08xYzZjbnl5N2tBbjBjN3JLUGdiVjFIMWJGd3MiLCJhY2Nlc3MiOlt7InR5cGUiOiJyZXBvc2l0b3J5IiwibmFtZSI6InNhbWFsYmEvbXktYXBwIiwiYWN0aW9ucyI6WyJwdXNoIl19XX0.QhflHPfbd6eVF4lM9bwYpFZIV0PfikbyXuLx959ykRTBpe3CYnzs6YBK8FToVb5R47920PVLrh8zuLzdCr9t3w"}
 | 
						|
```
 | 
						|
 | 
						|
## Using the signed token
 | 
						|
 | 
						|
Once the client has a token, it will try the registry request again with the
 | 
						|
token placed in the HTTP `Authorization` header like so:
 | 
						|
 | 
						|
```
 | 
						|
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiIsImtpZCI6IkJWM0Q6MkFWWjpVQjVaOktJQVA6SU5QTDo1RU42Ok40SjQ6Nk1XTzpEUktFOkJWUUs6M0ZKTDpQT1RMIn0.eyJpc3MiOiJhdXRoLmRvY2tlci5jb20iLCJzdWIiOiJCQ0NZOk9VNlo6UUVKNTpXTjJDOjJBVkM6WTdZRDpBM0xZOjQ1VVc6NE9HRDpLQUxMOkNOSjU6NUlVTCIsImF1ZCI6InJlZ2lzdHJ5LmRvY2tlci5jb20iLCJleHAiOjE0MTUzODczMTUsIm5iZiI6MTQxNTM4NzAxNSwiaWF0IjoxNDE1Mzg3MDE1LCJqdGkiOiJ0WUpDTzFjNmNueXk3a0FuMGM3cktQZ2JWMUgxYkZ3cyIsInNjb3BlIjoiamxoYXduOnJlcG9zaXRvcnk6c2FtYWxiYS9teS1hcHA6cHVzaCxwdWxsIGpsaGF3bjpuYW1lc3BhY2U6c2FtYWxiYTpwdWxsIn0.Y3zZSwaZPqy4y9oRBVRImZyv3m_S9XDHF1tWwN7mL52C_IiA73SJkWVNsvNqpJIn5h7A2F8biv_S2ppQ1lgkbw
 | 
						|
```
 | 
						|
 | 
						|
This is also described in [Section 2.1 of RFC 6750: The OAuth 2.0 Authorization Framework: Bearer Token Usage](https://tools.ietf.org/html/rfc6750#section-2.1)
 | 
						|
 | 
						|
## Verifying the token
 | 
						|
 | 
						|
The registry must now verify the token presented by the user by inspecting the
 | 
						|
claim set within. The registry will:
 | 
						|
 | 
						|
- Ensure that the issuer (`iss` claim) is an authority it trusts.
 | 
						|
- Ensure that the registry identifies as the audience (`aud` claim).
 | 
						|
- Check that the current time is between the `nbf` and `exp` claim times.
 | 
						|
- If enforcing single-use tokens, check that the JWT ID (`jti` claim) value has
 | 
						|
  not been seen before.
 | 
						|
  - To enforce this, the registry may keep a record of `jti`s it has seen for
 | 
						|
    up to the `exp` time of the token to prevent token replays.
 | 
						|
- Check the `access` claim value and use the identified resources and the list
 | 
						|
  of actions authorized to determine whether the token grants the required
 | 
						|
  level of access for the operation the client is attempting to perform.
 | 
						|
- Verify that the signature of the token is valid.
 | 
						|
 | 
						|
At no point in this process should the registry need to <em>call back</em> to
 | 
						|
the authorization server. If anything, it would only need to update a list of
 | 
						|
trusted public keys for verifying token signatures or use a separate API
 | 
						|
(still to be spec'd) to add/update resource records on the authorization
 | 
						|
server.
 |