DCG OAuth2 Setup and Usage

This topic provides a general overview and a technical explanation of OAuth2 authentication for the Digital Commerce Gateway.

The documentation in this section applies only to customers who have purchased the Digital Commerce Gateway license. The instructions provided don’t work without the Digital Commerce Gateway license.

Note

Prerequisites 

To use the information in this document, you must have previously requested and obtained a DCG environment. After the environment is provisioned, Salesforce sends you the following information:

  • The DCG Endpoint

    • Format: api.{myenv}.{customername}.dc.vloc-dev.com

      or

      api.{myenv}.{customername}.dc.vloc-prod.com

  • The OAuth2 Server

    • Format: vlocity-dc-{customername}-{platform}.auth.{region}.awscognito.com.com
  • Four sets of OAuth2 credentials for this environment:

    • admin

    • cmig

    • ops

    • user

List of the DCG endpoints and associated scopes 

You will find the mapping between app clients, scopes, and endpoints below. For each endpoint, you will find the list of methods authorized with which app client and scopes.

1# App clients and matching scopes access
2oauth2-{env}-admin = [admin, ops, user, cmig]
3oauth2-{env}-cmig  = [cmig]
4oauth2-{env}-ops   = [ops, user]
5oauth2-{env}-user  = [user]
6 
7# Scopes
8 - admin 
9 - cmig 
10 - ops 
11 - user
1# Digital Commerce
2/dc/app-status
3    OPTIONS no-auth (AWS Mock 200)
4    ANY     oauth2-{env}:[admin, ops]
5/dc/app-diagnostic
6    OPTIONS no-auth (AWS Mock 200)
7    ANY     oauth2-{env}:[admin, ops]
8/dc/{proxy}+
9    OPTIONS no-auth (AWS Mock 200)
10    DELETE  oauth2-{env}:[admin, ops]
11    PATCH   oauth2-{env}:[admin, ops]
12    ANY     oauth2-{env}:[admin, ops, user] 
13
14# Cache Migration
15/cm/app-status
16    OPTIONS no-auth (AWS Mock 200)
17    ANY     oauth2-{env}: [admin, ops]
18/cm/app-diagnostic
19    OPTIONS no-auth (AWS Mock 200)
20    ANY     oauth2-{env}: [admin, ops]
21/cm/{proxy}+
22    OPTIONS no-auth (AWS Mock 200)
23    DELETE  oauth2-{env}: [admin, cmig]
24    PATCH   oauth2-{env}: [admin, cmig]
25    ANY     oauth2-{env}: [admin, cmig, ops] 
26
27# Cache Administration
28/admin/cache/status
29    OPTIONS no-auth (AWS Mock 200)
30    GET     oauth2-{env}: [admin, ops] 
31
32/admin/cache/list
33    OPTIONS no-auth (AWS Mock 200)
34    GET     oauth2-{env}: [admin, ops] 
35
36/admin/cache/flush
37    OPTIONS no-auth (AWS Mock 200)
38    POST    oauth2-{env}: [admin, ops]

OAuth2 Description 

“Cognito Application Clients” customer keys and secrets are:

OAuth2 description

  • Used to request an OAuth2 JWT to the AWS Cognito OAuth2 server.

  • Generated by Salesforce and provided to the customer.

  • Specific to each environment.

OAuth2 JWT (JSON Web Token):

  • The OAuth2 JWT are temporary authorization code used to access the DCG API Endpoints.

  • These are obtained from the AWS Cognito OAuth2 server by a trusted client application.

  • The DCG OAuth2 JWT can be reused multiple times until its expiration date and can be shared by several application clients to connect to the same API.

  • The expiration time of the JWT is 3600 seconds (1 hour) and cannot be changed at the moment (AWS Cognito constraint).

The JSON Web Token or Bearer Token received from the OAuth2 server (also known as the AWS Cognito server) contains the following (among other things):

  • A string identifying the customer application used to deliver the token

  • A timestamp and expiration date

  • A scope or list of scopes that this token grants access to

  • A signature (to prevent JWT forgery)

You can find more information about OAuth2 JWT here: https://oauth.net/2/jwt/.

DCG uses OAuth2 Scopes to control access to the protected resource. Each Application Client is granted a list of scopes represented by arbitrary strings. The protected resources are assigned one or more scopes for specific paths. The scope, being part of the JWT content, the protected resource can validate whether the client has access to and/or requested access to this specific resource.

Implementation of OAuth2 for Digital Commerce 

Below is a sample procedure with example calls to obtain and consequently use an OAuth2 JWT token against a sample test deployment.

  • Obtain an OAuth2 JWT access token: Obtaining an OAuth2 JWT access token requires making a POST HTTPS request to the AWS OAuth2 Cognito endpoint using a specific set of credentials which Salesforce has created and provided. These credentials are referred to as customer application secrets.

    Multiple sets of secrets with different access levels are provided.

    1# "Cognito Application Clients": customer application secrets
    2customer_app_key="6gi8...imprk"
    3customer_app_secret="1dh9t...4iu2rn"
    4 
    5# cognito_oauth2_server (provided by Salesforce, below is an example)
    6cognito_oauth2_server="vl-dc-test.auth.eu-central-1.amazoncognito.com"
    7 
    8# Template curl call to retrieve an oauth2 token
    9curl -s -X POST --user "${customer_app_key}:${customer_app_secret}" \
    10    -H 'Content-Type: application/x-www-form-urlencoded' \
    11    
    12"https://${cognito_oauth2_server}/oauth2/token?grant_type=client_credentials"
    13 
    14# Response template:
    15{
    16  "access_token": "[...]",
    17  "expires_in": 3600,
    18  "token_type": "Bearer"}
    19 
    20# Example call
    21curl -s -X POST --user "6gi88ku...9imprk:1dh9to...0j4iu2rn" \
    22    -H 'Content-Type: application/x-www-form-urlencoded' \
    23"https://vl-dc-test.auth.eu-central-1.amazoncognito.com/oauth2/token?grant_type=client_credentials"
    24 
    25# Example response:{"access_token":"eyJraWQiOiJQbGkyTkJcL3NBczBabkVWaXdPS0ZhQ0JsbWpHcUxXblFOMlo0RmE1d09Ecz0iLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiI2Z2k4OGt1bmdkbmI0NDB0OWdpYzlpbXByayIsInRva2VuX3VzZSI6ImFjY2VzcyIsInNjb3BlIjoiZGMtdGVzdC1hcGlcL2FkbWluIGRjLXRlc3QtYXBpXC9yZWFkIGRjLXRlc3QtYXBpXC93cml0ZSIsImF1dGhfdGltZSI6MTU2MzM3NjMxNiwiaXNzIjoiaHR0cHM6XC9cL2NvZ25pdG8taWRwLmV1LWNlbnRyYWwtMS5hbWF6b25hd3MuY29tXC9ldS1jZW50cmFsLTFfelJHb2dweHc4IiwiZXhwIjoxNTYzMzc5OTE2LCJpYXQiOjE1NjMzNzYzMTYsInZlcnNpb24iOjIsImp0aSI6IjFmYTU5YWQ1LTIwNDEtNDAyZS04NGIxLTExNjFjMWIxMmQ1YyIsImNsaWVudF9pZCI6IjZnaTg4a3VuZ2RuYjQ0MHQ5Z2ljOWltcHJrIn0.awj5M4AvLXbL7TJrPIQguEUv2ifFurmZnqZraoNy5g9UP365_vknj-hJrgFzZ4OtOYlopQTdMgD-8m1n7vVqwUPfywr8qK2bJHOS8Dm9WycNypnsiFYC4eIDHjLd2526-G63w6shTj4B53QmtpCzJF8lIvB9rGcsiQgxIlRNK9ZRSmc0opHZSLnts0xeLUvHCW5eb5Uys7eIY_MPtc6GAMca0A6AObxADdklHMYLLagvEZdPPtj-A-HG04jLuNCwcS3lpuhtmw7W0F0hgGhIIuI0ZQez7TxzdeaV2B3v9_P_dLPe18-3mD1BV0kZyjYqcZYqFo4nHSg-UT33FLByWg","expires_in":3600,"token_type":"Bearer"}
  • Use an OAuth2 JWT: The resource protected by OAuth2 tokens can be accessed after you have retrieved a valid OAuth2 bearer token (also known as a JWT):

    1# Obtain the FQDN of the resource to access / protect (in this case the DCG API)api_fqdn="api-test-cognito.platform.customer.dc.vloc-dev.com"
    2 
    3# Example of URL path of the resource to be accessed
    4url_path="/dc/app-status"
    5url_path="/dc/v3/catalogs/CATALOG_CODE/offers"
    6 
    7# The OAuth2 response from cognito is stored in the oauth2_cognito_response
    8oauth2_cognito_response='{"access_token":"[...]","expires_in":3600,"token_type":"Bearer"}'
    9 
    10# The OAuth2 token is stored in the variable oauth2_token
    11# Example of extraction of the access_token from oauth2_cognito_response via Python’s jq tool
    12oauth2_token="$(echo -e "$oauth2_cognito_response"  | jq -r .access_token )"
    13 
    14# Template for calls made to the protected resource:
    15curl -s -i -X GET -H "authorization: Bearer ${oauth2_token}" \
    16    -H "Content-Type: application/json; charset=UTF-8" \
    17    "https://${api_fqdn}${url_path}" ; echo -e "\n\nCurl returned $?"
    1# Example:
    2#  - Setting variables and contextapi_fqdn="api-test-cognito.platform.customer.dc.vloc-dev.com"
    3 
    4url_path="/dc/app-status"
    5 
    6oauth2_token="eyJraWQiOiJQbGkyTkJcL3NBczBabkVWaXdPS0ZhQ0JsbWpHcUxXblFOMlo0RmE1d09Ecz0iLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiI2Z2k4OGt1bmdkbmI0NDB0OWdpYzlpbXByayIsInRva2VuX3VzZSI6ImFjY2VzcyIsInNjb3BlIjoiZGMtdGVzdC1hcGlcL2FkbWluIGRjLXRlc3QtYXBpXC9yZWFkIGRjLXRlc3QtYXBpXC93cml0ZSIsImF1dGhfdGltZSI6MTU2MzM3NjMxNiwiaXNzIjoiaHR0cHM6XC9cL2NvZ25pdG8taWRwLmV1LWNlbnRyYWwtMS5hbWF6b25hd3MuY29tXC9ldS1jZW50cmFsLTFfelJHb2dweHc4IiwiZXhwIjoxNTYzMzc5OTE2LCJpYXQiOjE1NjMzNzYzMTYsInZlcnNpb24iOjIsImp0aSI6IjFmYTU5YWQ1LTIwNDEtNDAyZS04NGIxLTExNjFjMWIxMmQ1YyIsImNsaWVudF9pZCI6IjZnaTg4a3VuZ2RuYjQ0MHQ5Z2ljOWltcHJrIn0.awj5M4AvLXbL7TJrPIQguEUv2ifFurmZnqZraoNy5g9UP365_vknj-hJrgFzZ4OtOYlopQTdMgD-8m1n7vVqwUPfywr8qK2bJHOS8Dm9WycNypnsiFYC4eIDHjLd2526-G63w6shTj4B53QmtpCzJF8lIvB9rGcsiQgxIlRNK9ZRSmc0opHZSLnts0xeLUvHCW5eb5Uys7eIY_MPtc6GAMca0A6AObxADdklHMYLLagvEZdPPtj-A-HG04jLuNCwcS3lpuhtmw7W0F0hgGhIIuI0ZQez7TxzdeaV2B3v9_P_dLPe18-3mD1BV0kZyjYqcZYqFo4nHSg-UT33FLByWg"
    1#  - Running the command
    2curl -s -i -X GET -H "authorization: Bearer ${oauth2_token}" \
    3    -H "Content-Type: application/json; charset=UTF-8" \
    4    "https://${api_fqdn}${url_path}" ; echo -e "\n\nCurl returned $?"
    5 
    6#  - Received response
    7HTTP/2 200 
    8date: Mon, 10 Aug 2020 15:36:32 GMT
    9content-type: application/vnd.spring-boot.actuator.v2+json;charset=UTF-8
    10content-length: 586
    11x-amzn-requestid: 4c427148-f29e-4d34-b909-00594a31728d
    12x-amz-apigw-id: RD1r8GTePHcF4Yw=
    13x-amzn-lambda-integration-tag: 457b37f4-324c-4ba3-a405-e87945962669
    14vloc-op-cache: NOT_APPLICABLE
    15x-amzn-trace-id: Root=1-5f31697f-895fde273e05332417fd3f41 
    16
    17{"status":"UP","details":{"health":{"status":"UP","details":{"app_name":"Vlocity V3 Edge API","version":"1.0-SNAPSHOT","build_time":"2020-06-11T14:03:37Z","build_info":{"commit":"f925489","buildInfo":"tblanchard@tblanchard","branch":"v17","date":"2020-06-11T14:03:37Z"},"salesforce_last_contact":"","app_start_time":"2020-08-10T15:09:58.058Z","jks_expire_ms":"2022-03-22T09:16:52+0000"}},"redis":{"status":"UP","details":{"redis":"UP","hits":55516102,"misses":7363576,"evicted":0,"expired":178034,"hit_ratio":0.88,"con_active":0,"con_idle":0,"con_wait":0,"redis_pool_size":8}}}}
  • Scopes with different endpoints and app-clients: The resource protected by OAuth2 tokens can be accessed once we have retrieved a valid oauth2 bearer token.

    Not all app-clients give access to all resources; this allows you to share or use different app clients depending on your users.

    You will find the complete list of endpoints and scope access in the next section.

    The following is an example with the following 2 app clients

    1oauth2-myenv-ops   scope access: ops and user
    2oauth2-myenv-user  scope access: user

    The URL path /dc/app-status is accessible by all scopes (admin, ops, user).

    The URL path /dc/v3/catalogs/CATALOG_CODE/offers is accessible only by the admin and ops scopes.

    To set up different endpoints and app-clients:

    1cognito_oauth2_server="vl-dc-test.auth.eu-central-1.amazoncognito.com"
    2 
    3# We’ve created a second "Cognito Application Clients" with different scopes
    4# Retrieve and store a different JWT with each set of credentials
    5# Template curl call to retrieve an oauth2 token
    6curl -s -X POST --user "${customer_app_key}:${customer_app_secret}" -H
    7'Content-Type: application/x-www-form-urlencoded'
    8"https://${cognito_oauth2_server}/oauth2/token?grant_type=client_credentials"
    9 
    10# "Cognito Application Clients" oauth2-myenv-ops with ops and user scopes
    11customer_app_key="6gi88ku...9imprk"
    12customer_app_secret="1dh9to...0j4iu2rn"
    13 
    14oauth2_token_ops=[...]
    15 
    16# "Cognito Application Clients" oauth2-myenv-user with only user scope
    17customer_app_key="7j2o4n...4u97ri"
    18customer_app_secret="10m997...inlejh"
    19 
    20oauth2_token_user=[...]

    Responses received using the oauth2_token_user JWT from the  oauth2-myenv-user app client:

    • /dc/v3/catalogs/CATALOG_CODE/offers should return 200 unauthorized

    • /dc/app-status should return 401

    1api_fqdn="api-test-cognito.platform.customer.dc.vloc-dev.com"
    2 
    3url_path="/dc/v3/catalogs/CATALOG_CODE/offers"
    4curl -s -i -X GET -H "authorization: Bearer ${oauth2_token_user}" -H
    5"Content-Type: application/json; charset=UTF-8" "https://${api_fqdn}${url_path}" 
    6HTTP/2 200 
    7date: Mon, 22 Jul 2019 14:13:38 GMT
    8content-type: application/json;charset=ISO-8859-1
    9content-length: 12332
    10x-amzn-requestid: e65a90de-ac8a-11e9-93cd-9d8d58cb662d
    11x-amzn-remapped-content-length: 12332x-amz-apigw-id: dOum1EZeFiAFg8Q=
    12x-amzn-trace-id: Root=1-5d35c492-6dbf677d7c12525a746c90fe;Sampled=0
    13 
    14[...body...]
    15 
    16api_fqdn="api-test-cognito.platform.customer.dc.vloc-dev.com"
    17url_path="/dc/app-status"
    18curl -s -i -X GET -H "authorization: Bearer ${oauth2_token_user}" -H
    19"Content-Type: application/json; charset=UTF-8" "https://${api_fqdn}${url_path}"
    20 
    21HTTP/2 401 
    22date: Mon, 22 Jul 2019 14:13:32 GMT
    23content-type: application/json
    24content-length: 26
    25x-amzn-requestid: e2bf9017-ac8a-11e9-b915-3f49f14f8dec
    26x-amzn-errortype: UnauthorizedException
    27x-amz-apigw-id: dOul5H4YFiAFsxQ=
    28 
    29{"message":"Unauthorized"}

    Responses received using the oauth2_token_ops JWT from the  oauth2-myenv-ops app client:

    • /dc/v3/catalogs/CATALOG_CODE/offers should return 200

    • /dc/app-status should return 200

    1api_fqdn="api-test-cognito.platform.customer.dc.vloc-dev.com"
    2 
    3url_path=""
    4curl -s -i -X GET -H "authorization: Bearer ${oauth2_token_ops}" -H
    5"Content-Type: application/json; charset=UTF-8" "https://${api_fqdn}${url_path}"
    6 
    7HTTP/2 200 
    8date: Mon, 22 Jul 2019 14:30:16 GMT
    9content-type: application/json
    10content-length: 19
    11x-amzn-requestid: 3929aeba-ac8d-11e9-b4cd-11d6a4139ed9
    12x-amz-apigw-id: dOxCwFxMliAFZkw=
    13 
    14{"statusCode": 200}  
    15api_fqdn="api-test-cognito.platform.customer.dc.vloc-dev.com"
    16url_path="/dc/app-status"
    17curl -s -i -X GET -H "authorization: Bearer ${oauth2_token_user}" -H
    18"Content-Type: application/json; charset=UTF-8" "https://${api_fqdn}${url_path}"
    19 
    20HTTP/2 200 
    21date: Mon, 22 Jul 2019 14:32:38 GMT
    22content-type: application/json;charset=ISO-8859-1
    23content-length: 697
    24x-amzn-requestid: 8e0c7ccc-ac8d-11e9-b742-815dfc2c8abc
    25x-amzn-remapped-content-length: 697x-amz-apigw-id: dOxZBGEXliAFheg=
    26x-amzn-trace-id: Root=1-5d35c906-d3704ba9ad66385d1f8c14c6;Sampled=0

Troubleshooting 

If the application returns an HTTP status code other than 200 or 401, it may not be related to OAuth2 setup. For example, 403, 404, and 500 HTTP status codes are generally not related with OAuth2 setup or usage.

  • Error code 401: Access denied, see next section “Common 401 HTTP status code and errors returned by oauth2 auth“ for the different scenarios.

  • Error code 403: If you receive a code 403 from the DCG application, it generally means that there is a problem with the configuration of your client. It can be any of the following:

    • Wrong URL or path.

    • Missing or misspelled headers.

    • Client IP outside access list when allow list has been configured (endpoints are opened to the world by default).

  • Error code 5xx: These errors generally indicate an issue with the DC API request itself or the data sets retrieved. Please get in touch with Customer Support or Professional Services to solve them.

  • Common 401 HTTP status code and errors returned by oauth2 auth:

    • Expired token:

      1#  - declaring an expired token
      2oauth2_token="eyJraWQiOiJQbGkyTkJcL3NBczBabkVWaXdPS0ZhQ0JsbWpHcUxXblFOMlo0RmE1d09Ecz0iLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiI2Z2k4OGt1bmdkbmI0NDB0OWdpYzlpbXByayIsInRva2VuX3VzZSI6ImFjY2VzcyIsInNjb3BlIjoiZGMtdGVzdC1hcGlcL2FkbWluIGRjLXRlc3QtYXBpXC9yZWFkIGRjLXRlc3QtYXBpXC93cml0ZSIsImF1dGhfdGltZSI6MTU2MzM3NjMxNiwiaXNzIjoiaHR0cHM6XC9cL2NvZ25pdG8taWRwLmV1LWNlbnRyYWwtMS5hbWF6b25hd3MuY29tXC9ldS1jZW50cmFsLTFfelJHb2dweHc4IiwiZXhwIjoxNTYzMzc5OTE2LCJpYXQiOjE1NjMzNzYzMTYsInZlcnNpb24iOjIsImp0aSI6IjFmYTU5YWQ1LTIwNDEtNDAyZS04NGIxLTExNjFjMWIxMmQ1YyIsImNsaWVudF9pZCI6IjZnaTg4a3VuZ2RuYjQ0MHQ5Z2ljOWltcHJrIn0.awj5M4AvLXbL7TJrPIQguEUv2ifFurmZnqZraoNy5g9UP365_vknj-hJrgFzZ4OtOYlopQTdMgD-8m1n7vVqwUPfywr8qK2bJHOS8Dm9WycNypnsiFYC4eIDHjLd2526-G63w6shTj4B53QmtpCzJF8lIvB9rGcsiQgxIlRNK9ZRSmc0opHZSLnts0xeLUvHCW5eb5Uys7eIY_MPtc6GAMca0A6AObxADdklHMYLLagvEZdPPtj-A-HG04jLuNCwcS3lpuhtmw7W0F0hgGhIIuI0ZQez7TxzdeaV2B3v9_P_dLPe18-3mD1BV0kZyjYqcZYqFo4nHSg-UT33FLByWg"
      3 
      4#  - Running the command
      5curl -s -i -X GET -H "authorization: Bearer ${oauth2_token}" -H "Content-Type:
      6application/json; charset=UTF-8" "https://${api_fqdn}${url_path}" ; echo -e "\n\nCurl returned $?"
      7 
      8#  - Received response
      9HTTP/2 401 
      10date: Thu, 04 Jul 2019 12:35:15 GMT
      11content-type: application/json
      12content-length: 44
      13x-amzn-requestid: 2cd359f0-9e58-11e9-a702-3b62603f614d
      14x-amzn-errortype: UnauthorizedException
      15x-amz-apigw-id: cTLUlGjdliAFbig= 
      16
      17{"message":"The incoming token has expired"}
    • Malformed token: In the following example, remove some characters from the end of the base64 oauth2 token, in effect corrupting the signature.

      1#  - Received response
      2HTTP/2 403 
      3date: Mon, 22 Jul 2019 13:39:21 GMT
      4content-type: application/json
      5content-length: 27
      6x-amzn-requestid: 1c7a8f4b-ac86-11e9-b10d-e70db1458280
      7x-amzn-errortype: AccessDeniedException
      8x-amz-apigw-id: dOpleEcSFiAFdxg=
      9 
      10{"Message":"Access Denied"}
  • Invalid token: The token is not authorized to access this request (e.g. the scope of the Application Client does not grant access to a specific resource).

    1#  - Received response
    2HTTP/2 401
    3date: Wed, 03 Jul 2019 15:00:06 GMT
    4content-type: application/json
    5content-length: 26
    6x-amzn-requestid: 3ec26cce-9da3-11e9-8211-2d7edd287f91
    7x-amzn-errortype: UnauthorizedException
    8x-amz-apigw-id: cQNmlFoEFiAFppA= 
    9
    10{"message":"Unauthorized"}

See Also