diff --git a/ob_v3p0/images/OB3_CCG_ObtainingTokens.svg b/ob_v3p0/images/OB3_CCG_ObtainingTokens.svg new file mode 100644 index 00000000..fdcf841e --- /dev/null +++ b/ob_v3p0/images/OB3_CCG_ObtainingTokens.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/ob_v3p0/security.html b/ob_v3p0/security.html index c6a4094c..a9a02598 100644 --- a/ob_v3p0/security.html +++ b/ob_v3p0/security.html @@ -3,17 +3,280 @@

Open Badges API Security

- In scenarios where the learner or another third party is the [=user=] that owns the resources (badges), - there will not be a pre-established trust relationship. Therefore you MUST use of OAuth 2.0 Authorization - Code Grant. -

-

- The Open Badges API endpoints use the method outlined in Section 4.2, "Using OAuth 2.0 Authorization Code - Grant" of the [[[SEC-11]]] to secure the API endpoints. This section describes the how Authorization - Code Grant is implemented for the Open Badges API. + The Open Badges API endpoints use the methods outlined in Section 4, "Securing Web Services" of the [[[SEC-11]]]. [=Clients=] + and [=servers=] that have an established trust relationship and shared ownership of the resources (Open Badges) MUST + use the OAuth 2.0 Client-Credentials Grant method. [=Clients=] and [=servers=] that give + individual users control over access to their resources MUST use the OAuth 2.0 Authorization + Code Grant method.

+ + +
+

Using OAuth 2.0 Client-Credentials Grant

+ +

+ [=Clients=] and [=servers=] that have a pre-established trust relationship and shared ownership of the + protected resources (Comprehensive Learner Records) MUST use the OAuth 2.0 Client-Credentials Grant (CCG) + method. +

+

+ [=Clients=] and [=servers=] implementing this method of security MUST comply with Section 4.1, "Using OAuth + 2.0 Client-Credentials Grant" of the [[[SEC-11]]]. +

+ + +
+

CCG - Registration

+

+ To get started, the [=client=] and [=authorization server=] must share the four pieces of information + shown below. These can be shared manually or by using [[[#dynamic-registration]]]. +

+
+
client_id
+
+ This is the public identifier for the communication exchange. Also called a Secret in the + [[[SEC-11]]]. +
+
client_secret
+
+ This is the shared secret for the communication exchange. Also called a Secret in the [[[SEC-11]]]. +
+
List of Scopes
+
+ The list of scopes that identify the set of endpoints for which access permission is being + requested. +
+
OAuth 2.0 Access Token Service Endpoint
+
+ The endpoint from which the approved, requesting [=client=] can obtain an access token. +
+
+

+ If the [=client=] and [=authorization server=] support Token Revocation, they should also share: +

+
+
OAuth 2.0 Revocation Service Endpoint
+
+ The endpoint a [=client=] can use to revoke an access token. +
+
+
+ + +
+

CCG - Obtaining Tokens

+
+ Sequence diagram for obtaining an access token using the CCG flow +
Sequence diagram for obtaining an access token using the CCG flow
+
+

+ Obtaining an access token using client credentials is a simple, one step process. Once obtained, the + [=client=] can freely re-use the access token until the token's expiry time. When the token expires, the + [=client=] will need to obtain a new access token. +

+ +
CCG - Access Token Request
+

+ To obtain an access token, the [=client=] posts a "client_credentials" grant token request + to the [=OAuth 2.0 Access Token Service Endpoint=] established during + Registration. Requests for an access token MUST use an HTTP POST + over HTTPS and TLS 1.2 or 1.3 protocol. The [=client=] MUST use its [=client_id=] and + [=client_secret=] with the HTTP Basic Authentication method (as described in + [[RFC2617]]) for this request and MUST NOT put its key and secret into the request body. +

+

+ The set of request parameters (see Section 4.4 of [RFC6749]) used to request a CCG access token are + shown below. The request MUST use the POST method and the request parameters MUST be placed in the + request body and MUST NOT be sent as URL query parameters. +

+ + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescriptionRequired
grant_typeStringThe value MUST be set to "client_credentials"Required
scopeString + The space delimited list of scopes of the access request. +

+ The [=authorization server=] is responsible for validating the scopes identified in + the request and the response MUST include a scope parameter which confirms this list + or comprises a subset of the services requested. +

+
Required
+
+        POST /token HTTP/1.1
+        Host: auth.1edtech.org
+        Authorization: Basic YWQyMmU5ZjYxNzlhNzljODo5Y2MxYzEzY2NmZTAxYWQ1
+        Content-Type: application/x-www-form-urlencoded
+        
+        grant_type=client_credentials&?scope=https%3a%2f%2fpurl.imsglobal.org%2fspec%2fob%2fv3p0%2fscope%2freadonly
+      
+ +
CCG - Access Token Response
+

+ If the [=authorization server=] grants this request (see Section 5.1 in [[RFC6749]] for the detailed + description), it returns the HTTP 200 OK status code with content type + "application/json" + consisting of a JSON object containing the access token and its expiry lifetime (1EdTech recommends a + default expiry lifetime of 3600 seconds, one hour, for access tokens) and confirms the set of scopes + supported by this access token: +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Property NameTypeDescriptionRequired
access_tokenStringThe access token issued by the [=authorization server=].Required
token_typeStringThe type of the token issued. The case insensitive value MUST be "bearer".Required
scopeString + The space delimited list of scopes of the access token. The [=authorization server=] is + responsible for validating the scopes identified in the request and the response MUST + include a scope parameter which confirms this list or comprises a subset of the services + requested. + Required
expires_inPositiveInteger + The lifetime in seconds of the access token. For example, the value "3600" denotes that + the access token will expire in one hour from the time the response was generated. 1EdTech + recommends a default expiry lifetime of 3600 seconds, one hour, for access tokens. If + omitted, the authorization server SHOULD provide the expiration time via other means or + document the default value. + Optional
+
+        HTTP/1.1 200 OK
+        Content-Type: application/json; charset=UTF-8
+        Cache-Control: no-store
+        Pragma: no-cache
+        
+        {
+            "access_token": "863DF0B10F5D432EB2933C2A37CD3135A7BB7B07A68F65D92",
+            "expires_in": 3600,
+            "token_type": "Bearer",
+            "scope": "https://purl.imsglobal.org/spec/ob/v3p0/scope/readonly"
+        }
+      
+ +
Access Token Error Response
+

+ The [=authorization server=] MAY decide not to issue an access token. This could be because the + request scopes are invalid, the credentials from the client may be invalid, etc. In this case the + [=authorization server=] MUST return an HTTP 400 Bad Request status code with content + type "application/json" consisting of a JSON object describing the error in the response body. The + properties used to describe the error are: +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Property NameTypeDescriptionRequired
errorTokenError VocabularyA single ASCII [[RFC20]] error code. See Section 5.2 of [[RFC6749]].Required
error_descriptionASCIIString + Human-readable ASCII [RFC20] text providing additional information, used to assist the + client developer in understanding the error that occurred. Values for the + "error_description" parameter MUST NOT include characters outside the set %x20-21 / + %x23-5B / %x5D-7E. + Optional
error_uriURI + A URI identifying a human-readable web page with information about the error, used to + provide the client developer with additional information about the error. Values for the + "error_uri" parameter MUST conform to the URI-reference syntax and thus MUST NOT include + characters outside the set %x21 / %x23-5B / %x5D-7E. + Optional
+
+        HTTP/1.1 400 Bad Request
+        Content-Type: application/json;charset=UTF-8
+        Cache-Control: no-store
+        Pragma: no-cache
+
+        {
+            "error": "invalid_request"
+        }
+      
+ +
+ + +
+

CCG - Authenticating with Tokens

+

+ The [=client=] uses the access token to authenticate with the [=resource server=] using the HTTP + Authorization request header field [[RFC2617]] with a Bearer Token [[RFC6750]]. +

+
+        GET ims/ob/v3p0/credentials?limit=2&offset=0 HTTP/1.1
+        HOST: provider.1edtech.org
+        Authorization: Bearer 863DF0B10F5D432EB2933C2A37CD3135A7BB7B07A68F65D92
+        Accept: application/json
+      
+
+
+

Using OAuth 2.0 Authorization Code Grant

@@ -22,7 +285,7 @@

Using OAuth 2.0 Authorization Code Grant

  1. - [[[#acg-registration]]] - Share configuration information between the [=client=] and the [=server=]. + [[[#dynamic-registration]]] - Share configuration information between the [=client=] and the [=server=]. This is typically done only once unless the registration is revoked.
  2. @@ -37,7 +300,7 @@

    Using OAuth 2.0 Authorization Code Grant

    -

    Dynamic Client Registration

    +

    Dynamic Client Registration

    To get started, the [=client=] and [=authorization server=] MUST share the four pieces of information shown below using the OAuth 2.0 Dynamic Client Registration Protocol [[RFC7591]] as described in this @@ -98,7 +361,7 @@

    Request the Service Description Document

             GET /tenant/ims/ob/v3p0/discovery HTTP/1.1
    -        Host: example.com
    +        Host: 1edtech.org
             Accept: application/json
           

    @@ -189,10 +452,10 @@

    Request the Service Description Document

    ... "info": { - "x-imssf-image": "https://example.com/logo", - "x-imssf-privacyPolicy": "https://example.com/privacy", + "x-imssf-image": "https://1edtech.org/logo", + "x-imssf-privacyPolicy": "https://1edtech.org/privacy", "title": "Example", - "termsOfService": "https://example.com/tos", + "termsOfService": "https://1edtech.org/tos", ... }, ... @@ -201,12 +464,12 @@

    Request the Service Description Document

    "OAuth2ACG": { "type": "oauth2", "description": "OAuth 2.0 Authorization Code Grant authorization", - "x-imssf-registrationUrl": "example.com/registration", + "x-imssf-registrationUrl": "1edtech.org/registration", "flows": { "authorizationCode": { - "tokenUrl": "example.com/token", - "authorizationUrl": "example.com/authorize", - "refreshUrl": "example.com/token", + "tokenUrl": "1edtech.org/token", + "authorizationUrl": "1edtech.org/authorize", + "refreshUrl": "1edtech.org/token", "scopes": { "https://purl.imsglobal.org/spec/ob/v3p0/scope/assertion.update" : "...", "https://purl.imsglobal.org/spec/ob/v3p0/scope/assertion.readonly" : "...", @@ -253,7 +516,7 @@

    Register with Authorization Server

    The properties of the JSON body MUST be implemented as described in the following table. All URLs - MUST use HTTPS (e.g. https://example.com/logo.png) and all URLs MUST have the same hostname. All + MUST use HTTPS (e.g. https://1edtech.org/logo.png) and all URLs MUST have the same hostname. All required properties MUST be present in the registration request in order for it to be accepted by the [=authorization server=]. Arrays MUST be used even when a single value is to be sent.

    @@ -414,20 +677,20 @@

    Register with Authorization Server

             POST /connect/register HTTP/1.1
    -        Host: auth.example.com
    +        Host: auth.1edtech.org
             Accept: application/json
             Content-Type: application/json; charset=utf-8
             
             {
               "client_name": "Example Client Application",
    -          "client_uri": "https://client.example.com/",
    -          "logo_uri": "https://client.example.com/logo.png",
    -          "tos_uri": "https://client.example.com/terms",
    -          "policy_uri": "https://client.example.com/privacy",
    +          "client_uri": "https://client.1edtech.org/",
    +          "logo_uri": "https://client.1edtech.org/logo.png",
    +          "tos_uri": "https://client.1edtech.org/terms",
    +          "policy_uri": "https://client.1edtech.org/privacy",
               "software_id": "c88b6ed8-269e-448e-99be-7e2ff47167d1",
               "software_version": "v4.0.30319",
               "redirect_uris": [
    -            "https://client.example.com/Authorize"
    +            "https://client.1edtech.org/Authorize"
               ],
               "token_endpoint_auth_method": "client_secret_basic",
               "grant_types": [
    @@ -458,14 +721,14 @@ 

    Register with Authorization Server

    "client_id_issued_at": 1565715850, "client_secret_expires_at": 1597338250, "client_name": "Example Client Application", - "client_uri": "https://client.example.com/", - "logo_uri": "https://client.example.com/logo.png", - "tos_uri": "https://client.example.com/terms", - "policy_uri": "https://client.example.com/privacy", + "client_uri": "https://client.1edtech.org/", + "logo_uri": "https://client.1edtech.org/logo.png", + "tos_uri": "https://client.1edtech.org/terms", + "policy_uri": "https://client.1edtech.org/privacy", "software_id": "c88b6ed8-269e-448e-99be-7e2ff47167d1", "software_version": "v4.0.30319", "redirect_uris": [ - "https://client.example.com/Authorize" + "https://client.1edtech.org/Authorize" ], "token_endpoint_auth_method": "client_secret_basic", "grant_types": [ @@ -594,7 +857,7 @@
    Authorization Request

    After the [=client=] application is registered with the [=authorization server=] as described in - [[[#acg-registration]]], the [=client=] application then MAY initiate an authorization request + [[[#dynamic-registration]]], the [=client=] application then MAY initiate an authorization request as described in Section 4.2 of the IMS Security Framework [[SEC-11]] by redirecting the user to the authorizationUrl as declared in the [=resource server=]'s Service Description Document (SDD). @@ -649,7 +912,7 @@

    Authorization Request
    URL The [=client=] application's redirection endpoint. MUST match one of the - redirect_uris in the [[[#acg-registration]]] request. Although this is + redirect_uris in the [[[#dynamic-registration]]] request. Although this is optional in the IMS Security Framework [[SEC-11]], it is REQUIRED by this specification. @@ -703,11 +966,11 @@
    Authorization Request

             HTTP/1.1 302 Found
    -        Location: https://auth.example.com/authorize?
    +        Location: https://auth.1edtech.org/authorize?
               client_id=4ad36680810420ed
               &response_type=code
               &scope=https%3A%2F%2Fpurl.imsglobal.org%2Fspec%ob%2Fv3p0%2Fscope%2Fassertion.readonly%20offline_access
    -          &redirect_uri=https%3A%2F%client.example.com%2FAuthorize
    +          &redirect_uri=https%3A%2F%client.1edtech.org%2FAuthorize
               &state=26357667-94df-4a14-bcb1-f55449ddd98d
               &code_challenge=XeDw66i9FLjn7XaecT_xaFyUWWfUub02Kw118n-jbEs
               &code_challenge_method=S256    
    @@ -771,7 +1034,7 @@ 
    Authorization Response
             HTTP/1.1 302 Found
    -        Location https://client.example.com/Authorize?
    +        Location https://client.1edtech.org/Authorize?
               code=dcf95d196ae04d60aad7e19d18b9af755a7b593b680055158b8ad9c2975f0d86
               &scope=https%3A%2F%2Fpurl.imsglobal.org%2Fspec%ob%2Fv3p0%2Fscope%2Fassertion.readonly%20offline_access
               &state=26357667-94df-4a14-bcb1-f55449ddd98d
    @@ -841,7 +1104,7 @@ 
    Authorization Error Response
             HTTP/1.1 302 Found
    -        Location: https://client.example.com/cb?error=access_denied&state=xyz
    +        Location: https://client.1edtech.org/cb?error=access_denied&state=xyz
           
    Access Token Request
    @@ -897,13 +1160,13 @@
    Access Token Request
             POST /token HTTP/1.1
    -        Host: auth.example.com
    +        Host: auth.1edtech.org
             Authorization: Basic NDE2ZjI1YjhjMWQ5OThlODoxNWQ5MDA4NTk2NDdkZDlm
             Content-Type: application/x-www-form-urlencoded
             
             grant_type=authorization_code
               &code=7c7a73263ee14b2b48073d0615f286ec74f6636689046cb8dbede0b5e87a1338
    -          &redirect_uri=https%3A%2F%client.example.com%2FAuthorize
    +          &redirect_uri=https%3A%2F%client.1edtech.org%2FAuthorize
               &scope=https%3A%2F%2Fpurl.imsglobal.org%2Fspec%2Fob%2Fv3p0%2Fscope%2Fassertion.readonly+offline_access
               &code_verifier=mYUQfKNgI1lSbY8EqtvNHLPzu0x%2FcVKO3fpWnX4VE5I%3D
           
    @@ -1129,7 +1392,7 @@

    Token Refresh Request

           POST /token HTTP/1.1
    -      Host: auth.example.com
    +      Host: auth.1edtech.org
           Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
           Content-Type: application/x-www-form-urlencoded
           
    @@ -1192,7 +1455,7 @@ 

    Token Revocation Request

           POST /revoke HTTP/1.1
    -      Host: auth.example.com
    +      Host: auth.1edtech.org
           Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
           Content-Type: application/x-www-form-urlencoded