Step 3. Using an OAuth 2.0 JWT Bearer Token
You can authenticate a call to the SAP Customer Data Platform REST APIs by using an OAuth 2.0 JWT Bearer Token generated from the Server Application’s RSA Private Key value. In this case, the Bearer Token value needs to be copied into the Authorization HTTP Header.
There are two ways that you can build this Bearer Token.
The first is to use the User Key and Secret Key to perform a POST call to the OAuth 2.0 token endpoint, which will return an Access Token that will be valid for authenticating REST API calls during the ensuing 10 minutes.
The second way requires building a JWT Bearer Token by providing the User Key, Private Key, a nonce value, and the current timestamp in Unix epoch format.
3.1 Retrieve a JWT Bearer Token from the OAuth 2.0 token endpoint.
3.1.1 Let’s perform a POST REST call to the SAP Customer Data Platform OAuth 2.0 token endpoint to retrieve a ready to use JWT Bearer Token. The cURL command template for such call is:
1234567
curl --request POST \
--url https://oauth2.us1.gigya.com/oauth2/token \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data client_id=USER_KEY \
--data client_secret=SECRET_KEY \
--data grant_type=client_credentials
3.1.2 After replacing the USER_KEY and SECRET_KEY placeholders with their respective values, we got the cURL command below. When executed, it returns a ready-to-use Bearer Token in the response payload body:
123456
curl --request POST \
--url https://oauth2.us1.gigya.com/oauth2/token \
--data client_id=AI32XTaizCgb \
--data client_secret=tnhJ6U6NPAiGbAcX2nwu/7V/3VXp5Cmu \
--data grant_type=client_credentials
3.1.3 After executing this script, copy from the returned JSON payload the access_token attribute value to your text file, identified as the BEARER_TOKEN_1 placeholder. You will use it in the next section.
3.2 Building a JWT Bearer Token using the Private Key value.
3.2.1 Let’s start by building a bash script that will leverage some standard command line utilities to generate our JWT Bearer Token. Define a PK bash variable using the template below:
123456
PK=$(cat <<-EOM
PRIVATE_KEY
EOM
)
3.2.2 Now replace the PRIVATE_KEY placeholder with its value from your text file:
123456789101112131415161718192021222324252627282930313233
PK=$(cat <<-EOM
-----BEGIN PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDPiWzlOmMTdgok
W1k6sMHGXkEWEq2qN7S6gtajx9ZnSnpah1BbRHxoG3tZDUbg5+9TEYiX+d3y+GAf
vpQwjhPUJVM9EevFDqAA5DhVAbkHLchhWFH0Pd/CbnFSJtMq4Nan0WLAF7ADgqKz
NQ5isLr4Dw4URaUso8axQRxi1O1BBe1lXXEi0nSqgTGP9tVINWYUpyc1/GfnSjdg
/WWBorimHChyJ+2Z/WfjXjdzwrbB7u+n1t8w7gnAq2rSXYaRNvgpepo6gt94wWOH
7kxjNYTZAgdjzdXXvfdRiAGlpjMkqmLVW8RyZG/N/TNXK2rj4d1Lp/DWXzsms7QD
8hHGKXTXAgMBAAECggEABBy/MwrLvC7IyqmiUTH/1PQ4w/A0Ar0+o1RExOzVYcL6
PUfH66PZKmyI+12/Yf6wIYXY0aVNpMSpJ75F/3Ea3kd5dV26inNDIy4vTSsbxUZx
9wPVM+RZ+U21u+2X0S/jvci9wfxC+TIIeUnIcpb5gKedUGeE4cD104m5WN5kb4P4
BF7AC6cXcEs6nrEWXpPmakF/Hm3zSnYZDV+rpBN6w9tjPggxcpO5kOWGYET/IUwY
23WKVq021Jmh9OwImkOSS4GKVtZAKnUjllf4YSc4gmtzLiaFSJVjM0L+4ZuQXbn3
U9+CYHYmGwi2Z8487+QRoD7qxB8xdrNGC0u7jj7syQKBgQDlvOCIvUWIX+UpjLFA
4SVHirEXsIn2u0hrizhH3DHNgOFefQ91ilWr4a3ovjpZ/XiDRTKYQwXqFTXx7HTi
DL9i0pxGAb5kJqlTEwJOAR2ht+AKJ4XST1Q3FfyNdp7VAGBOygoP3HhISg5raUfQ
xGsAY5+dbslDwqjjdFSzdZfb1QKBgQDnQtnz3pCIRJBWpV/xwMkIoEtYrE75MWkm
0ZEHnfcy9GOJc2m2Zrczd2ZoJANBs7Ni+Is9x2VSr4HmeZCoAdmvnzXPCqPLzzcB
dUj6VlgP6R1qaLIa+K/5RhyszOLI2mCAa+iBD2l1yA8kj0FpDNqC81v82sKj3aXQ
QGkJ3b2/+wKBgAX3X8VtVO7zvpnTo47RygwPmAXLeenEd18DoJSNLWXu4Ot5R/t/
ejYaiE+xEQbhRE30cBnwM6ken+YGhAqS1i2U1qYiyXUEZAVaSwcHlGNsyQ66dAlA
Mim0EnkCCaHyfo3NRXGgAieudK1pcIoFb9n0vGJ0TBnMZmJx1PlMJoN5AoGAflW8
70aUunyKRWtOgKkKqdW3k5d+BRADG5u8mOao1oM/pSURiP2P82O05AtYZBohU13n
4zX8mjEay6d5aO6p1xEouhRb6skmiXtjBK8KqJZ25VyQf79/krPEknnTIlp6AW3x
tB+RQzCpZRWFbDgDXypHBFkVn6NEJAIr36HtOOUCgYBS1JGo1BKzMP5/ulM3lJri
oz/FUBsISC7D7DLEjwHe2gOw6xsu2eP6kC28wEq2p/O1nPx3AqIelnDlk6pw60TD
RXqsRPClGueU0QvxTpsdjZ29ZLpaaDqpZ+ijxX7rirYSfGVJSSNc/8NURg86MggL
/hHOh0MkYLuPlgjObrhA5w==
-----END PRIVATE KEY-----
EOM
)
3.2.3 The HEADER variable is a JSON block containing the JWT hash algorithm (RS256), the Key Id (the USER_KEY value of the CDP Server Application), and the token type (JWT). Here is the template for the HEADER variable.
1
HEADER='{"alg":"RS256","kid":"USER_KEY","typ":"JWT"}'
Note: learn more by reading the JWT RFC at https://datatracker.ietf.org/doc/html/rfc7519
3.2.4 Replace the USER_KEY placeholder in the HEADER variable by the corresponding value found in your placeholders text file.
1
HEADER='{"alg":"RS256","kid":"AI32XTaizCgb","typ":"JWT"}'
3.2.5 The following block contains the PAYLOAD variable of our JWT, which is formed by another JSON block containing the Issued At attribute, set to the value of the current Unix Epoch timestamp, and the JWT Id holding a nonce value:
1234
NOW=$(date +%s)
UUID=$(uuidgen)
PAYLOAD="{'iat':$NOW,'jti':'$UUID'}"
3.2.6 The HEADER_PAYLOAD variable contains the concatenated values of HEADER and PAYLOAD, each encoded in Base 64 and separated by a period to conform to the JWT tokenization format.
1
HEADER_PAYLOAD=$(echo -n $HEADER | b64enc).$(echo -n $PAYLOAD | b64enc)
3.2.7 The next line is where the JWT Header and Payload gets hashed with the Private Key contents to form the signature part of the JWT token. After that, its value gets encoded to Base 64 and stored into the SIGNATURE variable.
1
SIGNATURE=$(echo -n $HEADER_PAYLOAD | openssl dgst -binary -sha256 -sign <(echo -n "$PK") | b64enc)
3.2.8 Finally, the BEARER_TOKEN joins the values of HEADER_PAYLOAD and SIGNATURE, once again separated by a period character. Our OAuth 2.0 JWT Bearer Token is complete and ready to be used for authenticating an SAP Customer Data Platform API call.
123
BEARER_TOKEN=$HEADER_PAYLOAD.$SIGNATURE
echo $BEARER_TOKEN
3.2.9 Please see below a sample of the full bash script based on the steps above that will generate a Bearer Token:
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
#!/usr/bin/env bash
set -euo pipefail
b64enc() { openssl enc -base64 -A | tr '+/' '-_' | tr -d '='; }
PK=$(cat <<-EOM
-----BEGIN PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDPiWzlOmMTdgok
W1k6sMHGXkEWEq2qN7S6gtajx9ZnSnpah1BbRHxoG3tZDUbg5+9TEYiX+d3y+GAf
vpQwjhPUJVM9EevFDqAA5DhVAbkHLchhWFH0Pd/CbnFSJtMq4Nan0WLAF7ADgqKz
NQ5isLr4Dw4URaUso8axQRxi1O1BBe1lXXEi0nSqgTGP9tVINWYUpyc1/GfnSjdg
/WWBorimHChyJ+2Z/WfjXjdzwrbB7u+n1t8w7gnAq2rSXYaRNvgpepo6gt94wWOH
7kxjNYTZAgdjzdXXvfdRiAGlpjMkqmLVW8RyZG/N/TNXK2rj4d1Lp/DWXzsms7QD
8hHGKXTXAgMBAAECggEABBy/MwrLvC7IyqmiUTH/1PQ4w/A0Ar0+o1RExOzVYcL6
PUfH66PZKmyI+12/Yf6wIYXY0aVNpMSpJ75F/3Ea3kd5dV26inNDIy4vTSsbxUZx
9wPVM+RZ+U21u+2X0S/jvci9wfxC+TIIeUnIcpb5gKedUGeE4cD104m5WN5kb4P4
BF7AC6cXcEs6nrEWXpPmakF/Hm3zSnYZDV+rpBN6w9tjPggxcpO5kOWGYET/IUwY
23WKVq021Jmh9OwImkOSS4GKVtZAKnUjllf4YSc4gmtzLiaFSJVjM0L+4ZuQXbn3
U9+CYHYmGwi2Z8487+QRoD7qxB8xdrNGC0u7jj7syQKBgQDlvOCIvUWIX+UpjLFA
4SVHirEXsIn2u0hrizhH3DHNgOFefQ91ilWr4a3ovjpZ/XiDRTKYQwXqFTXx7HTi
DL9i0pxGAb5kJqlTEwJOAR2ht+AKJ4XST1Q3FfyNdp7VAGBOygoP3HhISg5raUfQ
xGsAY5+dbslDwqjjdFSzdZfb1QKBgQDnQtnz3pCIRJBWpV/xwMkIoEtYrE75MWkm
0ZEHnfcy9GOJc2m2Zrczd2ZoJANBs7Ni+Is9x2VSr4HmeZCoAdmvnzXPCqPLzzcB
dUj6VlgP6R1qaLIa+K/5RhyszOLI2mCAa+iBD2l1yA8kj0FpDNqC81v82sKj3aXQ
QGkJ3b2/+wKBgAX3X8VtVO7zvpnTo47RygwPmAXLeenEd18DoJSNLWXu4Ot5R/t/
ejYaiE+xEQbhRE30cBnwM6ken+YGhAqS1i2U1qYiyXUEZAVaSwcHlGNsyQ66dAlA
Mim0EnkCCaHyfo3NRXGgAieudK1pcIoFb9n0vGJ0TBnMZmJx1PlMJoN5AoGAflW8
70aUunyKRWtOgKkKqdW3k5d+BRADG5u8mOao1oM/pSURiP2P82O05AtYZBohU13n
4zX8mjEay6d5aO6p1xEouhRb6skmiXtjBK8KqJZ25VyQf79/krPEknnTIlp6AW3x
tB+RQzCpZRWFbDgDXypHBFkVn6NEJAIr36HtOOUCgYBS1JGo1BKzMP5/ulM3lJri
oz/FUBsISC7D7DLEjwHe2gOw6xsu2eP6kC28wEq2p/O1nPx3AqIelnDlk6pw60TD
RXqsRPClGueU0QvxTpsdjZ29ZLpaaDqpZ+ijxX7rirYSfGVJSSNc/8NURg86MggL
/hHOh0MkYLuPlgjObrhA5w==
-----END PRIVATE KEY-----
EOM
)
HEADER='{"alg":"RS256","kid":"AI32XTaizCgb","typ":"JWT"}'
NOW=$(date +%s)
UUID=$(uuidgen)
PAYLOAD="{'iat':$NOW,'jti':'$UUID'}"
HEADER_PAYLOAD=$(echo -n $HEADER | b64enc).$(echo -n $PAYLOAD | b64enc)
SIGNATURE=$(echo -n $HEADER_PAYLOAD | openssl dgst -binary -sha256 -sign <(echo -n "$PK") | b64enc)
BEARER_TOKEN=$HEADER_PAYLOAD.$SIGNATURE
echo $BEARER_TOKEN
3.2.10 After executing the full script you built by following the steps 3-b-i through 3-b-viii, store the result as the BEARER_TOKEN_2 placeholder in your text file. You’ll use it in the next section.
3.3 Calling an SAP Customer Data Platform REST API using an OAuth 2.0 JWT Bearer Token
3.3.1 Now let’s see how to use the Bearer Token to authenticate a REST API call to SAP Customer Data Platform. For this quick test, let’s use the REST API call that returns all customer profiles. The cURL command template for this call is:
123456
curl --request GET \
--url 'https://cdp.eu5.gigya.com/api/businessunits/4_iNfbhGDrBGciUrxckeBfJA/views/HAPxPF10AHr1bASCaGU_dQ/customers' \
--data-urlencode purposeIds=HFZPPZxxFQUebd3ksLoTaQ \
--data-urlencode query="SELECT * FROM Profiles" \
--header 'Authorization: Bearer BEARER_TOKEN'
3.3.2 You can replace the BEARER_TOKEN placeholder by the value of either BEARER_TOKEN_1 or BEARER_TOKEN_2 (they will both work). After replacing the BEARER_TOKEN symbol with an actual value, we got the following cURL command:
123456
curl --request GET \
--url 'https://cdp.eu5.gigya.com/api/businessunits/4_iNfbhGDrBGciUrxckeBfJA/views/HAPxPF10AHr1bASCaGU_dQ/customers' \
--data-urlencode purposeIds=HFZPPZxxFQUebd3ksLoTaQ \
--data-urlencode query="SELECT * FROM Profiles" \
--header 'Authorization: Bearer eyJhbGciOiJFUzI1NiIsImtpZCI6IkMyMzc4RUMyNTdDMkI3Mzc5NTYzNzI2RDU4QUM1Mzg0NTY3MUUyNDJCNTZDMkM0NTRCMEU2QjBBNUMzN0Q0RDkiLCJ0eXAiOiJhdCtqd3QifQ.eyJhdWQiOiJodHRwczovL2FwaS5naWd5YS5jb20iLCJzdWIiOiJBSTMyWFRhaXpDZ2IiLCJjbGllbnRfaWQiOiJBSTMyWFRhaXpDZ2IiLCJzY29wZSI6ImFwcGxpY2F0aW9uX2tleSIsImNsaWVudF9uYW1lIjoiQ0RQIGlkOiBITi1YR0pXLVFuYWtIbWFfT01MeWRRIiwibmJmIjoxNzI5MzI2NTkzLCJleHAiOjE3MjkzMjcxOTMsImlhdCI6MTcyOTMyNjU5MywiaXNzIjoiaHR0cHM6Ly9vYXV0aDIuZ2lneWEuY29tIn0.JE2vYErDkFj0ve0mLArj4ThEg_z3pzFqKq-7X83h1iX2Hbomf8g7RD8G1cHYdv3QivOYkWqJnF5dj_EldZCrsg'
After executing it, you will see a list of customer profiles in the returned JSON payload.
NOTE: Just keep in mind that the SAP Customer Data Platform Bearer Tokens expire 10 minutes after they’re created.