Customer Token

A customer token is part of the advanced customer authentication process. Bloomreach Engagement APIs use it instead of customer IDs. The customer token contains encoded customer IDs and a signature. When Bloomreach Engagement API receives a customer token, it first verifies the signature and only processes the request if the signature is valid.

If you want to learn more about the advanced authentication, read the App inbox article.

How does it work?

Customer tokens must be generated by a party that can securely verify the customer's identity. Usually, this means that customer tokens should be generated during the website or application backend login procedure. When the customer identity is verified (using password, 3rd party authentication, Single Sign-On), the website or application backend should generate the Bloomreach Engagement customer token and send it to the device running the Bloomreach Engagement JS or mobile SDK.

Customer identity verification

Customer tokens must be generated by a party that can also verify the customer's identity. Bloomreach Engagement cannot provide an API to generate customer tokens. Doing so would invalidate the security of the advanced authentication solution because the Bloomreach Engagement API cannot verify if a device or API request is allowed to use a particular customer ID.

Customer token generation

The customer token is encoded via JSON web token standard. Therefore, the generated customer token must comply with a specific schema in order to be decoded and to have verified customer IDs by Bloomreach Engagement API. The correct format of the required parameters can be found further in this section of the article.

Requirements

  • JWT header schema
  • JWT payload schema
  • JWT signature

Header schema

KeyValue
alg“HS256”
typ“JWT”
kidString - private API key ID. This is how Bloomreach Engagement API knows which secret should be used to verify the signature.

Payload schema

KeyValue
subObject - customer IDs, where the field name is the customer ID type, and the field value is the ID value. Multiple customer IDs can be specified in one token if needed.
expInteger, optional - seconds since the Unix epoch when the token expires.

Signature

For creating the signature, refer to JWS Message Signature or MAC Computation. Advanced customer authentication supports the “HS256” signing scheme.

Signing secret

The “HS256” signing scheme requires a secret shared for generating and validating the signature. Advanced customer authentication uses Bloomreach Engagement private API keys for this purpose.

Generate customer tokens

To generate the customer token:

  1. Check if you have a private API group set in your project as this is a requirement for getting the secret API key.
  2. Add a private API group key. Store its value securely. You will never be able to recover the value again.

  1. Now, you have a key that consists of the API key ID and API secret.

  2. Generate your customer token. Use the “API Key ID” value in the “kid” field of the JWT header and use the SHA256 checksum of the “API Secret” value to create a JWT signature (see an example below).

❗️

Remember

API Secret must never be shared or stored on an end-user device (mobile app, web browser).

  1. After creating the SHA-256 checksum of the private key, encode the JWT header and JWT payload parts (as specified above) as a JSON string. Then convert them both to an unpadded base64url and join them using a dot. To do so, follow these simple steps:
    • Use an HS256 (HMAC with SHA-256) signing method on the result from the 3rd step. Then use the SHA-256 checksum of the private key that was created in the 1st step.
    • Encode the customer token result from the previous step as an unpadded base64url and append it to the result from the 3rd step. Use a dot “.” as a separator.
    • Now you have the final customer token.

PyJWT library

Review the example of the result using PyJWT library.

import hashlib
import jwt


def customer_token(customer_ids: dict, api_key_id: str, api_key_secret: str, expire_time: int=None) -> str:
    header_data = {
        'alg': 'HS256',
        'typ': 'JWT',
        'kid': api_key_id,
    }
    claims_data = {
        'sub': customer_ids,
    }

    if expire_time:
        claims_data['exp']: expire_time

    # note: we must use SHA256 checksum of the api_key_secret as signing secret, not api_key_secret directly
    signing_key = hashlib.sha256(api_key_secret.encode()).hexdigest()
    return jwt.encode(claims_data, signing_key, headers=header_data, algorithm='HS256')

token = customer_token(
    customer_ids={"registered":"[email protected]"},
    api_key_id="example-api-key-id",
    api_key_secret="example-api-secret",
)
print(token)
# expected result:
# eyJhbGciOiJIUzI1NiIsImtpZCI6ImV4YW1wbGUtYXBpLWtleS1pZCIsInR5cCI6IkpXVCJ9.eyJzdWIiOnsicmVnaXN0ZXJlZCI6ImpvaG4uZG9lQGV4YW1wbGUuY29tIn19.e2spIFhcuoSuvXKWoquGBQNC35BAq_ixFCcYEGe0Roo