# User Payload

This section explains how will you generate user payload string that will be used in Config initialization. User payload generation is accomplished with the following 3 steps:

# Form Your User Data

The user payload must include the following fields in your data:

{
  "user_id": "string user id",
  "user_name": "string user name",
  "user_avatar_url": "string user avatar url",
  "user_followings": [
    "string user id 1",
    "string user id 2",
    "string user id 3"
  ],
  "user_creator_tags": [
    "string user creator tag 1",
    "string user creator tag 2",
    "string user creator tag 3"
  ],
  "user_consumer_tags": [
    "string user consumer tag 1",
    "string user consumer tag 2",
    "string user consumer tag 3"
  ],
  "expiration_time": integer timestamp in miliseconds
}

WARNING

All of the fields should be presented in your data.

# Encrypt Your Data

User payload should be encrypted using AES Encryption in CBC mode with 256 Key size in bits. The payload is encrypted with initialization-vector and secret-key. Initialization-vector is 16 characters long whereas secret-key is 32 characters. When the Storyly Moments instance is created, random initialization-vector and secret-keys are generated along with the Storyly Moments token.

You can use sample encryption functions:

WARNING

This sample contains code from CommonCrypto so you need to import it.

func encrypt(data: Data, operation: CCOperation) throws -> Data {
      var outLength = Int(0)
      var outBytes = [UInt8](repeating: 0, count: input.count + kCCBlockSizeAES128)
      var status: CCCryptorStatus = CCCryptorStatus(kCCSuccess)

      input.withUnsafeBytes { rawBufferPointer in
          let encryptedBytes = rawBufferPointer.baseAddress!

          Data(Array("Storyly Moments Initialization Vector".withUnsafeBytes { rawBufferPointer in
              let ivBytes = rawBufferPointer.baseAddress!

              Data(Array("Storyly Moments Secret Key".utf8)).withUnsafeBytes { rawBufferPointer in
                  let keyBytes = rawBufferPointer.baseAddress!

                  status = CCCrypt(operation,
                                    CCAlgorithm(kCCAlgorithmAES128),            
                                    CCOptions(kCCOptionPKCS7Padding),           
                                    keyBytes,                                   
                                    key.count,                                 
                                    ivBytes,                                    
                                    encryptedBytes,                             
                                    input.count,                                
                                    &outBytes,                                  
                                    outBytes.count,                             
                                    &outLength)                                 
              }
          }
      }

      guard status == kCCSuccess else { throw Error.cryptoFailed(status: status) }
      let encryptedData = Data(bytes: &outBytes, count: outLength)
      return encryptedData
  }
}

func encodeUserData(userData: [String: AnyHashable]) -> Data? {
    return try? JSONSerialization.data(withJSONObject: userPayload)
}

let sampleUserData: [String: AnyHashable] = [
    "user_id" to "string user id",
    "user_name" to "string user name",
    "user_avatar_url" to "string user avatar url",
    "user_followings" to [ "string user id 1" ...],
    "expiration_time" to integer timestamp in miliseconds
]
let encodedData = encode(userData: sampleUserData)
let encryptedData = try? encrypt(data: encodedData, operation: CCOperation(kCCEncrypt))

WARNING

The user payload is valid if it can be decrypted with the initialization vector and secret key of the Storyly Moments instance and if its expiration time is not expired.