From d8b59ab637434caa818ca4cc9f86625dc300e179 Mon Sep 17 00:00:00 2001 From: Derek McGowan Date: Thu, 11 Feb 2016 13:55:23 -0800 Subject: [PATCH 1/7] Add specification for using oauth with the token server Signed-off-by: Derek McGowan (github: dmcgowan) --- docs/spec/auth/index.md | 5 +- docs/spec/auth/oauth.md | 122 ++++++++++++++++++++++++++++++++++++++++ docs/spec/auth/token.md | 36 ++++++++++-- 3 files changed, 155 insertions(+), 8 deletions(-) create mode 100644 docs/spec/auth/oauth.md diff --git a/docs/spec/auth/index.md b/docs/spec/auth/index.md index 2d1740e88..e0e8aaf67 100644 --- a/docs/spec/auth/index.md +++ b/docs/spec/auth/index.md @@ -8,5 +8,6 @@ keywords = ["registry, on-prem, images, tags, repository, distribution, authenti # Docker Registry v2 authentication -See the [Token Authentication Specification](token.md) and -[Token Authentication Implementation](jwt.md) for more information. +See the [Token Authentication Specification](token.md), +[Token Authentication Implementation](jwt.md), and +[OAuth2 Token Authentication](oauth.md) for more information. diff --git a/docs/spec/auth/oauth.md b/docs/spec/auth/oauth.md new file mode 100644 index 000000000..56d7d943c --- /dev/null +++ b/docs/spec/auth/oauth.md @@ -0,0 +1,122 @@ + + +# Docker Registry v2 authentication using OAuth2 + +This document describes support for the OAuth2 protocol within the authorization +server. [RFC6749](https://tools.ietf.org/html/rfc6749) should be used as a +reference for the protocol and HTTP endpoints described here. + +## Refresh token format + +The format of the refresh token is completely opaque to the client and should be +determined by the authorization server. The authorization should ensure the +token is sufficiently long and is responsible for storing any information about +long-lived tokens which may be needed for revoking. Any information stored +inside the token will not be extracted and presented by clients. + +## Getting a token + +POST /token + +#### Headers +Authorization headers +Content-Type: application/x-www-form-urlencoded + +#### Post parameters + +
+
+ grant_type +
+
+ (REQUIRED) Type of grant used to get token. When getting a refresh token + using credentials this type should be set to "password" and have the + accompanying basic auth header. Type "authorization_code" is reserved + for future use for authenticating to an authorization server without + having to send credentials directly from the client. When requesting an + access token with a refresh token this should be set to "refresh_token". +
+
+ service +
+
+ (REQUIRED) The name of the service which hosts the resource to get + access for. Refresh tokens will only be good for getting tokens for + this service. +
+
+ client +
+
+ (REQUIRED) The name of the client which is getting accessed. Intended to be human + readable for key auditing. +
+
+ access_type +
+
+ (OPTIONAL) Access which is being requested. If "offline" is provided then a refresh + token will be returned. Otherwise only a short lived access token will + be returned. If the grant type is "refresh_token" this will only return + the same refresh token and not a new one. +
+
+ scope +
+
+ (OPTIONAL) The resource in question, formatted as one of the space-delimited + entries from the scope parameters from the WWW-Authenticate header + shown above. This query parameter should be specified multiple times if + there is more than one scope entry from the WWW-Authenticate + header. The above example would be specified as: + scope=repository:samalba/my-app:push. When requesting a refresh + token the scopes may be empty since the refresh token will not be limited by + this scope, only the provided short lived access token. +
+
+ refresh_token +
+
+ (OPTIONAL) The refresh token to use for authentication when grant type "refresh_token" is used. +
+
+ +#### Example getting refresh token + +``` +POST /token HTTP/1.1 +Host: auth.docker.io +Authorization: ... +Content-Type: application/x-www-form-urlencoded + +grant_type=password&service=hub.docker.io&client=dockerengine&access_type=offline + +HTTP/1.1 200 OK +Content-Type: application/json + +{"refresh_token":"xT2s5VFNrbzZTMVExUmpwWVRsSklPbFJMTmtnNlMxUkxOanBCUVV0VU1Ga3d","access_token":"eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCIsIng1YyI6WyJNSUlDTHpDQ0FkU2dBd0lCQWdJQkFEQUtCZ2dxaGtqT1BRUURBakJHTVVRd1FnWURWUVFERXp0Uk5Gb3pPa2RYTjBrNldGUlFSRHBJVFRSUk9rOVVWRmc2TmtGRlF6cFNUVE5ET2tGU01rTTZUMFkzTnpwQ1ZrVkJPa2xHUlVrNlExazFTekFlRncweE5UQTJNalV4T1RVMU5EWmFGdzB4TmpBMk1qUXhPVFUxTkRaYU1FWXhSREJDQmdOVkJBTVRPMGhHU1UwNldGZFZWam8yUVZkSU9sWlpUVEk2TTFnMVREcFNWREkxT2s5VFNrbzZTMVExUmpwWVRsSklPbFJMTmtnNlMxUkxOanBCUVV0VU1Ga3dFd1lIS29aSXpqMENBUVlJS29aSXpqMERBUWNEUWdBRXl2UzIvdEI3T3JlMkVxcGRDeFdtS1NqV1N2VmJ2TWUrWGVFTUNVMDByQjI0akNiUVhreFdmOSs0MUxQMlZNQ29BK0RMRkIwVjBGZGdwajlOWU5rL2pxT0JzakNCcnpBT0JnTlZIUThCQWY4RUJBTUNBSUF3RHdZRFZSMGxCQWd3QmdZRVZSMGxBREJFQmdOVkhRNEVQUVE3U0VaSlRUcFlWMVZXT2paQlYwZzZWbGxOTWpveldEVk1PbEpVTWpVNlQxTktTanBMVkRWR09saE9Va2c2VkVzMlNEcExWRXMyT2tGQlMxUXdSZ1lEVlIwakJEOHdQWUE3VVRSYU16cEhWemRKT2xoVVVFUTZTRTAwVVRwUFZGUllPalpCUlVNNlVrMHpRenBCVWpKRE9rOUdOemM2UWxaRlFUcEpSa1ZKT2tOWk5Vc3dDZ1lJS29aSXpqMEVBd0lEU1FBd1JnSWhBTXZiT2h4cHhrTktqSDRhMFBNS0lFdXRmTjZtRDFvMWs4ZEJOVGxuWVFudkFpRUF0YVJGSGJSR2o4ZlVSSzZ4UVJHRURvQm1ZZ3dZelR3Z3BMaGJBZzNOUmFvPSJdfQ.eyJhY2Nlc3MiOlt7InR5cGUiOiJyZXBvc2l0b3J5IiwibmFtZSI6ImRtY2dvd2FuL2hlbGxvLXdvcmxkIiwiYWN0aW9ucyI6WyJwdWxsIl19XSwiYXVkIjoicmVnaXN0cnkuZG9ja2VyLmlvIiwiZXhwIjoxNDU0NDM4Njc1LCJpYXQiOjE0NTQ0MzgzNzUsImlzcyI6ImF1dGguZG9ja2VyLmlvIiwianRpIjoiZXFrVmVsWWJtbW5KSDctNW53SEkiLCJuYmYiOjE0NTQ0MzgzNzUsInN1YiI6ImRtY2dvd2FuIn0"} +```` + +#### Example refreshing an Access Token + +```` +POST /token HTTP/1.1 +Host: auth.docker.io +Content-Type: application/x-www-form-urlencoded + +grant_type=refresh_token&refresh_token=kas9Da81Dfa8&service=registry-1.docker.io&client=dockerengine&scope=repository:samalba/my-app:pull,push + +HTTP/1.1 200 OK +Content-Type: application/json + +{"access_token":"eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCIsIng1YyI6WyJNSUlDTHpDQ0FkU2dBd0lCQWdJQkFEQUtCZ2dxaGtqT1BRUURBakJHTVVRd1FnWURWUVFERXp0Uk5Gb3pPa2RYTjBrNldGUlFSRHBJVFRSUk9rOVVWRmc2TmtGRlF6cFNUVE5ET2tGU01rTTZUMFkzTnpwQ1ZrVkJPa2xHUlVrNlExazFTekFlRncweE5UQTJNalV4T1RVMU5EWmFGdzB4TmpBMk1qUXhPVFUxTkRaYU1FWXhSREJDQmdOVkJBTVRPMGhHU1UwNldGZFZWam8yUVZkSU9sWlpUVEk2TTFnMVREcFNWREkxT2s5VFNrbzZTMVExUmpwWVRsSklPbFJMTmtnNlMxUkxOanBCUVV0VU1Ga3dFd1lIS29aSXpqMENBUVlJS29aSXpqMERBUWNEUWdBRXl2UzIvdEI3T3JlMkVxcGRDeFdtS1NqV1N2VmJ2TWUrWGVFTUNVMDByQjI0akNiUVhreFdmOSs0MUxQMlZNQ29BK0RMRkIwVjBGZGdwajlOWU5rL2pxT0JzakNCcnpBT0JnTlZIUThCQWY4RUJBTUNBSUF3RHdZRFZSMGxCQWd3QmdZRVZSMGxBREJFQmdOVkhRNEVQUVE3U0VaSlRUcFlWMVZXT2paQlYwZzZWbGxOTWpveldEVk1PbEpVTWpVNlQxTktTanBMVkRWR09saE9Va2c2VkVzMlNEcExWRXMyT2tGQlMxUXdSZ1lEVlIwakJEOHdQWUE3VVRSYU16cEhWemRKT2xoVVVFUTZTRTAwVVRwUFZGUllPalpCUlVNNlVrMHpRenBCVWpKRE9rOUdOemM2UWxaRlFUcEpSa1ZKT2tOWk5Vc3dDZ1lJS29aSXpqMEVBd0lEU1FBd1JnSWhBTXZiT2h4cHhrTktqSDRhMFBNS0lFdXRmTjZtRDFvMWs4ZEJOVGxuWVFudkFpRUF0YVJGSGJSR2o4ZlVSSzZ4UVJHRURvQm1ZZ3dZelR3Z3BMaGJBZzNOUmFvPSJdfQ.eyJhY2Nlc3MiOlt7InR5cGUiOiJyZXBvc2l0b3J5IiwibmFtZSI6ImRtY2dvd2FuL2hlbGxvLXdvcmxkIiwiYWN0aW9ucyI6WyJwdWxsIl19XSwiYXVkIjoicmVnaXN0cnkuZG9ja2VyLmlvIiwiZXhwIjoxNDU0NDM4Njc1LCJpYXQiOjE0NTQ0MzgzNzUsImlzcyI6ImF1dGguZG9ja2VyLmlvIiwianRpIjoiZXFrVmVsWWJtbW5KSDctNW53SEkiLCJuYmYiOjE0NTQ0MzgzNzUsInN1YiI6ImRtY2dvd2FuIn0"} +```` + diff --git a/docs/spec/auth/token.md b/docs/spec/auth/token.md index 61e893c04..a953ede2a 100644 --- a/docs/spec/auth/token.md +++ b/docs/spec/auth/token.md @@ -91,6 +91,8 @@ challenge, the client will need to make a `GET` request to the URL ## Requesting a Token +Defines getting a bearer and refresh token using the token endpoint. + #### Query Parameters
@@ -100,6 +102,15 @@ challenge, the client will need to make a `GET` request to the URL
The name of the service which hosts the resource.
+
+ offline_token +
+
+ Whether to return a refresh token along with the bearer token. A refresh + token is capable of getting additional bearer tokens for the same + subject with different scopes. The refresh token does not have an + expiration and should be considered completely opaque to the client. +
scope
@@ -109,7 +120,9 @@ challenge, the client will need to make a `GET` request to the URL shown above. This query parameter should be specified multiple times if there is more than one scope entry from the WWW-Authenticate header. The above example would be specified as: - scope=repository:samalba/my-app:push. + scope=repository:samalba/my-app:push. The scope field may + be empty to request a refresh token without providing any resource + permissions to the returned bearer token.
@@ -150,6 +163,16 @@ challenge, the client will need to make a `GET` request to the URL standard time at which a given token was issued. If issued_at is omitted, the expiration is from when the token exchange completed. +
+ refresh_token +
+
+ (Optional) Token which can be used to get additional access tokens for + the same subject with different scopes. This token should be kept secure + by the client and only sent to the authorization server which issues + bearer tokens. This field will only be set when `offline_token=true` is + provided in the request. +
#### Example @@ -161,11 +184,12 @@ https://auth.docker.io/token?service=registry.docker.io&scope=repository:samalba ``` The token server should first attempt to authenticate the client using any -authentication credentials provided with the request. As of Docker 1.8, the -registry client in the Docker Engine only supports Basic Authentication to -these token servers. If an attempt to authenticate to the token server fails, -the token server should return a `401 Unauthorized` response indicating that -the provided credentials are invalid. +authentication credentials provided with the request. From Docker 1.11 the +Docker engine supports both Basic Authentication and [OAuth2](oauth.md) for +getting tokens. Docker 1.10 and before, the registry client in the Docker Engine +only supports Basic Authentication. If an attempt to authenticate to the token +server fails, the token server should return a `401 Unauthorized` response +indicating that the provided credentials are invalid. Whether the token server requires authentication is up to the policy of that access control provider. Some requests may require authentication to determine From 32931689d59270867ad82673f87f6133799a7079 Mon Sep 17 00:00:00 2001 From: Derek McGowan Date: Wed, 3 Feb 2016 11:19:37 -0800 Subject: [PATCH 2/7] Add scope documentation Signed-off-by: Derek McGowan (github: dmcgowan) --- docs/spec/auth/index.md | 3 +- docs/spec/auth/scope.md | 133 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 docs/spec/auth/scope.md diff --git a/docs/spec/auth/index.md b/docs/spec/auth/index.md index e0e8aaf67..b123af1ae 100644 --- a/docs/spec/auth/index.md +++ b/docs/spec/auth/index.md @@ -9,5 +9,6 @@ keywords = ["registry, on-prem, images, tags, repository, distribution, authenti # Docker Registry v2 authentication See the [Token Authentication Specification](token.md), -[Token Authentication Implementation](jwt.md), and +[Token Authentication Implementation](jwt.md), +[Token Scope Documentation](scope.md), [OAuth2 Token Authentication](oauth.md) for more information. diff --git a/docs/spec/auth/scope.md b/docs/spec/auth/scope.md new file mode 100644 index 000000000..3bc941c18 --- /dev/null +++ b/docs/spec/auth/scope.md @@ -0,0 +1,133 @@ + + +# Docker Registry Token Scope and Access + +Tokens used by the registry are always restricted what resources they may +be used to access, where those resources may be accessed, and what actions +may be done on those resources. Tokens always have the context of a user which +the token was originally created for. This document describes how these +restrictions are represented and enforced by the authorization server and +resource providers. + +## Scope Components + +### Subject (Authenticated User) + +The subject represents the user for which a token is valid. Any actions +performed using an access token should be considered on behalf of the subject. +This is included in the `sub` field of access token JWT. A refresh token should +be limited to a single subject and only be able to give out access tokens for +that subject. + +### Audience (Resource Provider) + +The audience represents a resource provider which is intended to be able to +perform the actions specified in the access token. Any resource provider which +does not match the audience should not use that access token. The audience is +included in the `aud` field of the access token JWT. A refresh token should be +limited to a single audience and only be able to give out access tokens for that +audience. + +### Resource Type + +The resource type represents the type of resource which the resource name is +intended to represent. This type may be specific to a resource provider but must +be understood by the authorization server in order to validate the subject +is authorized for a specific resource. + +#### Example Resource Types + + - `repository` - represents a single repository within a registry. A +repository may represent many manifest or content blobs, but the resource type +is considered the collections of those items. Actions which may be performed on +a `repository` are `pull` for accessing the collection and `push` for adding to +it. + +### Resource Name + +The resource name represent the name which identifies a resource for a resource +provider. A resource is identified by this name and the provided resource type. +An example of a resource name would be the name component of an image tag, such +as "samalba/myapp". + +### Resource Actions + +The resource actions define the actions which the access token allows to be +performed on the identified resource. These actions are type specific but will +normally have actions identifying read and write access on the resource. Example +for the `repository` type are `pull` for read access and `push` for write +access. + +## Authorization Server Use + +Each access token request may include a scope and an audience. The subject is +always derived from the passed in credentials or refresh token. When using +a refresh token the passed in audience must match the audience defined for +the refresh token. The audience (resource provider) is provided using the +`service` field. Multiple resource scopes may be provided using multiple `scope` +fields. The fields may be passed in as either `GET` query parameters or `POST` +form parameters. + +### Resource Scope Grammar + +``` +resourcescope := resourcetype ":" resourcename ":" resourceactions +resourcetype := /[a-z]*/ +resourcename := component [ '/' component ]* +resourceactions := action [ ',' action ]* +action := /[a-z]*/ +component := alpha-numeric [separator alpha-numeric]* +alpha-numeric := /[a-z0-9]+/ +separator := /[_.]|__|[-]*/ +``` +Full reference grammar is defined +(here)[https://godoc.org/github.com/docker/distribution/reference]. Currently +the scope name grammar is a subset of the reference grammar without support +for hostnames. + +## Resource Provider Use + +Once a resource provider has verified the authenticity of the scope through +JWT access token verification, the resource provider must ensure that scope +satisfies the request. The resource provider should match the given audience +according to name or URI the resource provider uses to identify itself. Any +denial based on subject is not defined here and is up to resource provider, the +subject is mainly provided for audit logs and any other user-specific rules +which may need to be provided but are not defined by the authorization server. + +The resource provider must ensure that ANY resource being accessed as the +result of a request has the appropriate access scope. Both the resource type +and resource name must match the accessed resource and an appropriate action +scope must be included. + +When appropriate authorization is not provided either due to lack of scope +or missing token, the resource provider to return a `WWW-AUTHENTICATE` HTTP +header with the `realm` as the authorization server, the `service` as the +expected audience identifying string, and a `scope` field for each required +resource scope to complete the request. + +## JWT Access Tokens + +Each JWT access token may only have a single subject and audience but multiple +resource scopes. The subject and audience are put into standard JWT fields +`sub` and `aud`. The resource scope is put into the `access` field. The +structure of the access field can be seen in the +[jwt documentation](jwt.md). + +## Refresh Tokens + +A refresh token must be defined for a single subject and audience. Further +restricting scope to specific type, name, and actions combinations should be +done by fetching an access token using the refresh token. Since the refresh +token is not scoped to specific resources for an audience, extra care should +be taken to only use the refresh token to negotiate new access tokens directly +with the authorization server, and never with a resource provider. + From 6d6c37c06a052e41ec3d65ae1615de95d9dd0a3b Mon Sep 17 00:00:00 2001 From: Derek McGowan Date: Thu, 11 Feb 2016 13:13:06 -0800 Subject: [PATCH 3/7] Update client section Use client_id as defined in oauth rfc instead of custom client field Signed-off-by: Derek McGowan (github: dmcgowan) --- docs/spec/auth/oauth.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/docs/spec/auth/oauth.md b/docs/spec/auth/oauth.md index 56d7d943c..2f561b2ed 100644 --- a/docs/spec/auth/oauth.md +++ b/docs/spec/auth/oauth.md @@ -53,11 +53,14 @@ Content-Type: application/x-www-form-urlencoded this service.
- client + client_id
- (REQUIRED) The name of the client which is getting accessed. Intended to be human - readable for key auditing. + (REQUIRED) String identifying the client. This client_id does not need + to be registered with the authorization server but should be set to a + meaningful value in order to allow auditing keys created by unregistered + clients. Accepted syntax is defined in + [RFC6749 Appendix A.1](https://tools.ietf.org/html/rfc6749#appendix-A.1)
access_type @@ -97,7 +100,7 @@ Host: auth.docker.io Authorization: ... Content-Type: application/x-www-form-urlencoded -grant_type=password&service=hub.docker.io&client=dockerengine&access_type=offline +grant_type=password&service=hub.docker.io&client_id=dockerengine&access_type=offline HTTP/1.1 200 OK Content-Type: application/json @@ -112,7 +115,7 @@ POST /token HTTP/1.1 Host: auth.docker.io Content-Type: application/x-www-form-urlencoded -grant_type=refresh_token&refresh_token=kas9Da81Dfa8&service=registry-1.docker.io&client=dockerengine&scope=repository:samalba/my-app:pull,push +grant_type=refresh_token&refresh_token=kas9Da81Dfa8&service=registry-1.docker.io&client_id=dockerengine&scope=repository:samalba/my-app:pull,push HTTP/1.1 200 OK Content-Type: application/json From 3fc4e4cdc860d47baf24facf0e2d3751d2de6b26 Mon Sep 17 00:00:00 2001 From: Derek McGowan Date: Fri, 12 Feb 2016 14:35:38 -0800 Subject: [PATCH 4/7] Add resource scope list definition Allow providing multiple scopes in a single scope string Signed-off-by: Derek McGowan (github: dmcgowan) --- docs/spec/auth/scope.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/spec/auth/scope.md b/docs/spec/auth/scope.md index 3bc941c18..353451921 100644 --- a/docs/spec/auth/scope.md +++ b/docs/spec/auth/scope.md @@ -73,16 +73,17 @@ always derived from the passed in credentials or refresh token. When using a refresh token the passed in audience must match the audience defined for the refresh token. The audience (resource provider) is provided using the `service` field. Multiple resource scopes may be provided using multiple `scope` -fields. The fields may be passed in as either `GET` query parameters or `POST` -form parameters. +fields on the `GET` request. The `POST` request only takes in a single +`scope` field but may use the resource scope list format to specify +multiple resource scopes. ### Resource Scope Grammar ``` -resourcescope := resourcetype ":" resourcename ":" resourceactions +resourcescopelist := resourcescope [ ',' action ]* [ ',' resourcescope]* +resourcescope := resourcetype ":" resourcename ":" action resourcetype := /[a-z]*/ resourcename := component [ '/' component ]* -resourceactions := action [ ',' action ]* action := /[a-z]*/ component := alpha-numeric [separator alpha-numeric]* alpha-numeric := /[a-z0-9]+/ From d51f76f90379c11c0a6be95a38e53e2f129da4ba Mon Sep 17 00:00:00 2001 From: Derek McGowan Date: Fri, 12 Feb 2016 16:04:11 -0800 Subject: [PATCH 5/7] Update oauth documentation to include returned scope Add post response values Update password grant type to match oauth spec Signed-off-by: Derek McGowan (github: dmcgowan) --- docs/spec/auth/oauth.md | 103 ++++++++++++++++++++++++++++++++-------- 1 file changed, 84 insertions(+), 19 deletions(-) diff --git a/docs/spec/auth/oauth.md b/docs/spec/auth/oauth.md index 2f561b2ed..b0f9a13f2 100644 --- a/docs/spec/auth/oauth.md +++ b/docs/spec/auth/oauth.md @@ -27,7 +27,6 @@ inside the token will not be extracted and presented by clients. POST /token #### Headers -Authorization headers Content-Type: application/x-www-form-urlencoded #### Post parameters @@ -39,10 +38,11 @@ Content-Type: application/x-www-form-urlencoded
(REQUIRED) Type of grant used to get token. When getting a refresh token using credentials this type should be set to "password" and have the - accompanying basic auth header. Type "authorization_code" is reserved - for future use for authenticating to an authorization server without - having to send credentials directly from the client. When requesting an - access token with a refresh token this should be set to "refresh_token". + accompanying username and password paramters. Type "authorization_code" + is reserved for future use for authenticating to an authorization server + without having to send credentials directly from the client. When + requesting an access token with a refresh token this should be set to + "refresh_token".
service @@ -66,10 +66,10 @@ Content-Type: application/x-www-form-urlencoded access_type
- (OPTIONAL) Access which is being requested. If "offline" is provided then a refresh - token will be returned. Otherwise only a short lived access token will - be returned. If the grant type is "refresh_token" this will only return - the same refresh token and not a new one. + (OPTIONAL) Access which is being requested. If "offline" is provided + then a refresh token will be returned. The default is "online" only + returning short lived access token. If the grant type is "refresh_token" + this will only return the same refresh token and not a new one.
scope @@ -77,12 +77,15 @@ Content-Type: application/x-www-form-urlencoded
(OPTIONAL) The resource in question, formatted as one of the space-delimited entries from the scope parameters from the WWW-Authenticate header - shown above. This query parameter should be specified multiple times if - there is more than one scope entry from the WWW-Authenticate - header. The above example would be specified as: - scope=repository:samalba/my-app:push. When requesting a refresh - token the scopes may be empty since the refresh token will not be limited by - this scope, only the provided short lived access token. + shown above. This query parameter should only be specified once but may + contain multiple scopes using the scope list format defined in the scope + grammar. If multiple scope is provided from + WWW-Authenticate header the scopes should first be + converted to a scope list before requesting the token. The above example + would be specified as: scope=repository:samalba/my-app:push. + When requesting a refresh token the scopes may be empty since the + refresh token will not be limited by this scope, only the provided short + lived access token will have the scope limitation.
refresh_token @@ -90,22 +93,84 @@ Content-Type: application/x-www-form-urlencoded
(OPTIONAL) The refresh token to use for authentication when grant type "refresh_token" is used.
+
+ username +
+
+ (OPTIONAL) The username to use for authentication when grant type "password" is used. +
+
+ password +
+
+ (OPTIONAL) The password to use for authentication when grant type "password" is used. +
+#### Response fields + +
+
+ access_token +
+
+ (REQUIRED) An opaque Bearer token that clients should + supply to subsequent requests in the Authorization header. + This token should not be attempted to be parsed or understood by the + client but treated as opaque string. +
+
+ scope +
+
+ (REQUIRED) The scope granted inside the access token. This may be the + same scope as requested or a subset. This requirement is stronger than + specified in [RFC6749 Section 4.2.2](https://tools.ietf.org/html/rfc6749#section-4.2.2) + by strictly requiring the scope in the return value. +
+
+ expires_in +
+
+ (REQUIRED) The duration in seconds since the token was issued that it + will remain valid. When omitted, this defaults to 60 seconds. For + compatibility with older clients, a token should never be returned with + less than 60 seconds to live. +
+
+ issued_at +
+
+ (Optional) The RFC3339-serialized UTC + standard time at which a given token was issued. If issued_at is omitted, the + expiration is from when the token exchange completed. +
+
+ refresh_token +
+
+ (Optional) Token which can be used to get additional access tokens for + the same subject with different scopes. This token should be kept secure + by the client and only sent to the authorization server which issues + bearer tokens. This field will only be set when `access_type=offline` is + provided in the request. +
+
+ + #### Example getting refresh token ``` POST /token HTTP/1.1 Host: auth.docker.io -Authorization: ... Content-Type: application/x-www-form-urlencoded -grant_type=password&service=hub.docker.io&client_id=dockerengine&access_type=offline +grant_type=password&username=johndoe&password=A3ddj3w&service=hub.docker.io&client_id=dockerengine&access_type=offline HTTP/1.1 200 OK Content-Type: application/json -{"refresh_token":"xT2s5VFNrbzZTMVExUmpwWVRsSklPbFJMTmtnNlMxUkxOanBCUVV0VU1Ga3d","access_token":"eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCIsIng1YyI6WyJNSUlDTHpDQ0FkU2dBd0lCQWdJQkFEQUtCZ2dxaGtqT1BRUURBakJHTVVRd1FnWURWUVFERXp0Uk5Gb3pPa2RYTjBrNldGUlFSRHBJVFRSUk9rOVVWRmc2TmtGRlF6cFNUVE5ET2tGU01rTTZUMFkzTnpwQ1ZrVkJPa2xHUlVrNlExazFTekFlRncweE5UQTJNalV4T1RVMU5EWmFGdzB4TmpBMk1qUXhPVFUxTkRaYU1FWXhSREJDQmdOVkJBTVRPMGhHU1UwNldGZFZWam8yUVZkSU9sWlpUVEk2TTFnMVREcFNWREkxT2s5VFNrbzZTMVExUmpwWVRsSklPbFJMTmtnNlMxUkxOanBCUVV0VU1Ga3dFd1lIS29aSXpqMENBUVlJS29aSXpqMERBUWNEUWdBRXl2UzIvdEI3T3JlMkVxcGRDeFdtS1NqV1N2VmJ2TWUrWGVFTUNVMDByQjI0akNiUVhreFdmOSs0MUxQMlZNQ29BK0RMRkIwVjBGZGdwajlOWU5rL2pxT0JzakNCcnpBT0JnTlZIUThCQWY4RUJBTUNBSUF3RHdZRFZSMGxCQWd3QmdZRVZSMGxBREJFQmdOVkhRNEVQUVE3U0VaSlRUcFlWMVZXT2paQlYwZzZWbGxOTWpveldEVk1PbEpVTWpVNlQxTktTanBMVkRWR09saE9Va2c2VkVzMlNEcExWRXMyT2tGQlMxUXdSZ1lEVlIwakJEOHdQWUE3VVRSYU16cEhWemRKT2xoVVVFUTZTRTAwVVRwUFZGUllPalpCUlVNNlVrMHpRenBCVWpKRE9rOUdOemM2UWxaRlFUcEpSa1ZKT2tOWk5Vc3dDZ1lJS29aSXpqMEVBd0lEU1FBd1JnSWhBTXZiT2h4cHhrTktqSDRhMFBNS0lFdXRmTjZtRDFvMWs4ZEJOVGxuWVFudkFpRUF0YVJGSGJSR2o4ZlVSSzZ4UVJHRURvQm1ZZ3dZelR3Z3BMaGJBZzNOUmFvPSJdfQ.eyJhY2Nlc3MiOlt7InR5cGUiOiJyZXBvc2l0b3J5IiwibmFtZSI6ImRtY2dvd2FuL2hlbGxvLXdvcmxkIiwiYWN0aW9ucyI6WyJwdWxsIl19XSwiYXVkIjoicmVnaXN0cnkuZG9ja2VyLmlvIiwiZXhwIjoxNDU0NDM4Njc1LCJpYXQiOjE0NTQ0MzgzNzUsImlzcyI6ImF1dGguZG9ja2VyLmlvIiwianRpIjoiZXFrVmVsWWJtbW5KSDctNW53SEkiLCJuYmYiOjE0NTQ0MzgzNzUsInN1YiI6ImRtY2dvd2FuIn0"} +{"refresh_token":"kas9Da81Dfa8","access_token":"eyJhbGciOiJFUzI1NiIsInR5","expires_in":"900","scope":""} ```` #### Example refreshing an Access Token @@ -120,6 +185,6 @@ grant_type=refresh_token&refresh_token=kas9Da81Dfa8&service=registry-1.docker.io HTTP/1.1 200 OK Content-Type: application/json -{"access_token":"eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCIsIng1YyI6WyJNSUlDTHpDQ0FkU2dBd0lCQWdJQkFEQUtCZ2dxaGtqT1BRUURBakJHTVVRd1FnWURWUVFERXp0Uk5Gb3pPa2RYTjBrNldGUlFSRHBJVFRSUk9rOVVWRmc2TmtGRlF6cFNUVE5ET2tGU01rTTZUMFkzTnpwQ1ZrVkJPa2xHUlVrNlExazFTekFlRncweE5UQTJNalV4T1RVMU5EWmFGdzB4TmpBMk1qUXhPVFUxTkRaYU1FWXhSREJDQmdOVkJBTVRPMGhHU1UwNldGZFZWam8yUVZkSU9sWlpUVEk2TTFnMVREcFNWREkxT2s5VFNrbzZTMVExUmpwWVRsSklPbFJMTmtnNlMxUkxOanBCUVV0VU1Ga3dFd1lIS29aSXpqMENBUVlJS29aSXpqMERBUWNEUWdBRXl2UzIvdEI3T3JlMkVxcGRDeFdtS1NqV1N2VmJ2TWUrWGVFTUNVMDByQjI0akNiUVhreFdmOSs0MUxQMlZNQ29BK0RMRkIwVjBGZGdwajlOWU5rL2pxT0JzakNCcnpBT0JnTlZIUThCQWY4RUJBTUNBSUF3RHdZRFZSMGxCQWd3QmdZRVZSMGxBREJFQmdOVkhRNEVQUVE3U0VaSlRUcFlWMVZXT2paQlYwZzZWbGxOTWpveldEVk1PbEpVTWpVNlQxTktTanBMVkRWR09saE9Va2c2VkVzMlNEcExWRXMyT2tGQlMxUXdSZ1lEVlIwakJEOHdQWUE3VVRSYU16cEhWemRKT2xoVVVFUTZTRTAwVVRwUFZGUllPalpCUlVNNlVrMHpRenBCVWpKRE9rOUdOemM2UWxaRlFUcEpSa1ZKT2tOWk5Vc3dDZ1lJS29aSXpqMEVBd0lEU1FBd1JnSWhBTXZiT2h4cHhrTktqSDRhMFBNS0lFdXRmTjZtRDFvMWs4ZEJOVGxuWVFudkFpRUF0YVJGSGJSR2o4ZlVSSzZ4UVJHRURvQm1ZZ3dZelR3Z3BMaGJBZzNOUmFvPSJdfQ.eyJhY2Nlc3MiOlt7InR5cGUiOiJyZXBvc2l0b3J5IiwibmFtZSI6ImRtY2dvd2FuL2hlbGxvLXdvcmxkIiwiYWN0aW9ucyI6WyJwdWxsIl19XSwiYXVkIjoicmVnaXN0cnkuZG9ja2VyLmlvIiwiZXhwIjoxNDU0NDM4Njc1LCJpYXQiOjE0NTQ0MzgzNzUsImlzcyI6ImF1dGguZG9ja2VyLmlvIiwianRpIjoiZXFrVmVsWWJtbW5KSDctNW53SEkiLCJuYmYiOjE0NTQ0MzgzNzUsInN1YiI6ImRtY2dvd2FuIn0"} +{"refresh_token":"kas9Da81Dfa8","access_token":"eyJhbGciOiJFUzI1NiIsInR5":"expires_in":"900","scope":"repository:samalba/my-app:pull,repository:samalba/my-app:push"} ```` From 66d6eaa83f6ddb51a204f58f5dcbf84d32052c83 Mon Sep 17 00:00:00 2001 From: Derek McGowan Date: Thu, 3 Mar 2016 17:38:12 -0800 Subject: [PATCH 6/7] Update scope list to use space separator The oauth spec defines using a space to separate parts of a scope. To better comply with future implementations built on oauth use a space to separate the resource scopes. Signed-off-by: Derek McGowan (github: dmcgowan) --- docs/spec/auth/scope.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/spec/auth/scope.md b/docs/spec/auth/scope.md index 353451921..76e6f8cf9 100644 --- a/docs/spec/auth/scope.md +++ b/docs/spec/auth/scope.md @@ -74,18 +74,18 @@ a refresh token the passed in audience must match the audience defined for the refresh token. The audience (resource provider) is provided using the `service` field. Multiple resource scopes may be provided using multiple `scope` fields on the `GET` request. The `POST` request only takes in a single -`scope` field but may use the resource scope list format to specify -multiple resource scopes. +`scope` field but may use a space to separate a list of multiple resource +scopes. ### Resource Scope Grammar ``` -resourcescopelist := resourcescope [ ',' action ]* [ ',' resourcescope]* -resourcescope := resourcetype ":" resourcename ":" action +scope := resourcescope [ ' ' resourcescope ]* +resourcescope := resourcetype ":" resourcename ":" action [ ',' action ]* resourcetype := /[a-z]*/ resourcename := component [ '/' component ]* action := /[a-z]*/ -component := alpha-numeric [separator alpha-numeric]* +component := alpha-numeric [ separator alpha-numeric ]* alpha-numeric := /[a-z0-9]+/ separator := /[_.]|__|[-]*/ ``` From 093fbdbfc40f8cc1774cb10a550030d440cf7de2 Mon Sep 17 00:00:00 2001 From: Derek McGowan Date: Wed, 9 Mar 2016 12:35:20 -0800 Subject: [PATCH 7/7] Add client_id to get token endpoint Signed-off-by: Derek McGowan (github: dmcgowan) --- docs/spec/auth/token.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/spec/auth/token.md b/docs/spec/auth/token.md index a953ede2a..9f3167be7 100644 --- a/docs/spec/auth/token.md +++ b/docs/spec/auth/token.md @@ -111,6 +111,16 @@ Defines getting a bearer and refresh token using the token endpoint. subject with different scopes. The refresh token does not have an expiration and should be considered completely opaque to the client. +
+ client_id +
+
+ String identifying the client. This client_id does not need + to be registered with the authorization server but should be set to a + meaningful value in order to allow auditing keys created by unregistered + clients. Accepted syntax is defined in + [RFC6749 Appendix A.1](https://tools.ietf.org/html/rfc6749#appendix-A.1). +
scope