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 @@
- 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.
+ [=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]]].
+
+ 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]]].
+
+ If the [=client=] and [=authorization server=] support Token Revocation, they should also share:
+
+ 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.
+
+ 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
+ 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.
+
+ 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.
+
+ If the [=authorization server=] grants this request (see Section 5.1 in [[RFC6749]] for the detailed
+ description), it returns the
+ 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
+ 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]].
+ Open Badges API Security
Using OAuth 2.0 Client-Credentials Grant
+
+ CCG - Registration
+
+
+
+
+ CCG - Obtaining Tokens
+
+ CCG - Access Token Request
+ [=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.
+
+
+
+
+
+
+
+ Parameter
+ Type
+ Description
+ Required
+
+
+
+ grant_type
String
+ The value MUST be set to "client_credentials"
+ Required
+
+
+
+
+ scope
String
+
+ The space delimited list of scopes of the access request.
+
+ 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
+ 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 Name
+ Type
+ Description
+ Required
+
+
+
+ access_token
String
+ The access token issued by the [=authorization server=].
+ Required
+
+
+
+ token_type
String
+ The type of the token issued. The case insensitive value MUST be "bearer".
+ Required
+
+
+
+ scope
String
+
+ 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_in
PositiveInteger
+
+ 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
+ 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 Name
+ Type
+ Description
+ Required
+
+
+
+ error
TokenError Vocabulary
+ A single ASCII [[RFC20]] error code. See Section 5.2 of [[RFC6749]].
+ Required
+
+
+
+ error_description
ASCIIString
+
+ 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_uri
URI
+
+ 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
+
+ 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
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 @@
GET /tenant/ims/ob/v3p0/discovery HTTP/1.1 - Host: example.com + Host: 1edtech.org Accept: application/json
@@ -189,10 +452,10 @@
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 @@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 - @@ -703,11 +966,11 @@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.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=xyzAccess 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