Analytics & Reports
Analytics
StoreFront

Security

Since order history is private information, all requests must be authenticated. In the traditional method where you are using a UI server, you can simply pass your clientKey in the header of the request.

If you are using Storefront or other front-end implementation, then you will need to generate a securedPayload to authenticate the user.

A private (authenticated with client key) and public endpoint exists for all retrieval APIs.

If you are passing the data through a UI server and authenticating with a clientKey, reference the Private Retrieval Endpoints.

If you are letting the front-end directly request data from cloud, then read the next section on Generating a Secured Payload, and reference the Public Retrieval Endpoints.

Generating a Secured Payload

When a user logs in on the site, the log in service on your site needs to generate a securedPayload based on the user’s information.

Sample Plain Text Message
{
  "userId": "626f6240676d61696c2e636f6d",
  "loyaltyId": "34313633353739353130",
  "expiration": 1504720404379
}

You must include at least one of userId or loyaltyId, and an expiration timestamp. The securedPayload will no longer work after the set expiration time.

Here are the steps for generating the securedPayload from the plain text message. We can provide a library that implements the process.

initialValueRaw = PRNG(128-bit)

initialValue = Base64Encode(initialValueRaw)


keyEncryption = PBKDF2WithHmacSHA1(--clientKey--, "--customerId--1Encryption", 5000 iterations)

keyMAC = PBKDF2WithHmacSHA1(–clientKey–, “–customerId–1MessageAuthenticationCode”, 5000 iterations)


cipherTextRaw = AES-CBC-PKCS7Padding(keyEncryption, initialValueRaw, plainTextMessage)

cipherText = Base64Encode(cipherTextRaw)


messageAuthenticationCodeRaw = HmacSHA256(keyMAC, cipherTextRaw + initialValueRaw)

messageAuthenticationCode = Base64Encode(messageAuthenticationCodeRaw)

Security Warning

A new initial value must be generated for each new securedPayload generated. The encryption key and MAC key need to be different as well, so different filler text is added to each.

Failure to do so WILL make the usage of this token insecure.

You will then need to send the securedPayload in the following format to the front-end, which it can then use to retrieve data as needed.

Sample Secured Payload
{
  "securedPayload": {
    "messageAuthenticationCode": "fJ7lXBJgJdF9K1m+RPVLZlc9ORYDbI=",
    "initialValue": "vDn1PwcE6KLyHtSWf0ASrQ==",
    "cipherText": "j2H7BnJTbA+T+yhDbC1P+/zhPvRAT5NLjwOQhTltonEnhoxthaPRwxfD30r\nugtQ5latIr+j4bLawHpsDbC1P+/zhPvR7DHFd/9GcZeCCZyeMygOzSN2ht+nbgSb3qLqM8O4Hm4wTFNR4IGgf08ifG5norc15Zmmunks7\n2tjfUHkg6hZpYnOpLdo="
  }
}

Testing with Secured Payload

There is a encrypt and decrypt endpoint for testing and debugging. Do NOT use the encrypt endpoint as your means of encrypting the payload.

Generate Secured Payload for Testing

Sample Request
curl
curl -X POST \
        --header 'Authorization: --clientKey--' \
        --H 'Content-Type: application/json' \
        --data '{}'
        "https://--customerId--.groupbycloud.com/orders/v1/securityToken"
Sample Body
    {
        "userId": "626f6240676d61696c2e636f6d",
        "loyaltyId": "34313633353739353130",
        "expirationDeltaMillis": 10000,
    }

The expirationDeltaMillis is optional, the default is 8 hours.

Sample Response
{
  "result": {
    "cipherText": "lFSe/4ryvXEI2afJ2oPVCr7SGbu+5k5U4LShbh86JFdnrgcIWmW8FRpeuu3WDEItWP3LexH4CwyhTEzyHNxpyEihXUbpzlZPIGjighxjXUbOMqvQRzPGTxbu68V4ySNthdE/U0Tt9RAubxHsCUz9WNhhZdUdfoHvnxu7WHCkuJY=",
    "initialValue": "tnRtL9kxDsIwMAtxQKiMKQ==",
    "messageAuthenticationCode": "fWRfU86osO5Tsl24m6OFCDn7voFho+aQOr6sCdhkKzU="
  },
  "status": {
    "code": 200,
    "internalCode": 0,
    "message": "OK",
    "additionalInfo": null,
    "serverTimestamp": 1523903745000
  }
}

Decrypt Secured Payload for Debugging

Sample Request
curl
curl -X POST \
        --header 'Authorization: --clientKey--' \
        --H 'Content-Type: application/json' \
        --data '{}'
        "https://--customerId--.groupbycloud.com/orders/v1/securityToken/decrypt"
Sample Body
{
  "cipherText": "lFSe/4ryvXEI2afJ2oPVCr7SGbu+5k5U4LShbh86JFdnrgcIWmW8FRpeuu3WDEItWP3LexH4CwyhTEzyHNxpyEihXUbpzlZPIGjighxjXUbOMqvQRzPGTxbu68V4ySNthdE/U0Tt9RAubxHsCUz9WNhhZdUdfoHvnxu7WHCkuJY=",
  "initialValue": "tnRtL9kxDsIwMAtxQKiMKQ==",
  "messageAuthenticationCode": "fWRfU86osO5Tsl24m6OFCDn7voFho+aQOr6sCdhkKzU="
}
Sample Response
{
  "result": {
    "loyaltyId": "eecd88f5a7c530be7923ccaac711767847a6da7f3a6ea0d4dae9db4552bdb4ad",
    "userId": "1e5847500d76893b7eeec35436b6dd4f22ce25736d3451ec550c3314c4b3ac3c",
    "expiration": 1524671390302
  },
  "status": {
    "code": 200,
    "internalCode": 0,
    "message": "OK",
    "additionalInfo": null,
    "serverTimestamp": 1524674814030
  }
}
`expiration` versus `expirationDeltaMillis`

When generating the token itself, you need to use an absolute expiration time.The test endpoint uses expirationDeltaMillis to make testing easier.