API login

To access the zeuz base API directly, you must write a script to log into zeuz and generate a request-hash. You use the request-hash to create a session key to attach to your API requests. The session key is valid for 24 hours.

The steps and code snippets in C++ below show you what must be in your login script. They cover task 3. Log in to zeuz and generate a session key, listed in API authentication.

See Example code for a full working example that covers the following two tasks listed in API authentication: 3. Log in to zeuz and generate a session key and 4. Generate a sign-hash to attach to your API requests.

Warning: You may not need a login script.

See Do I need a login script? below.

Info: Do I need a login script?

Before you start, see the API introduction to check whether you can access the zeuz API using one of the wrappers provided in the SDK download or the SDK in Go. If you can use a wrapper or the SDK in Go you don’t need to write your own authentication scripts.

You must access the zeuz base API directly if:

  • You develop your game in a language other than Unity, Unreal, or Go, or
  • You want to use the zeuz API to build tools around your game, for example to integrate your game into your CI/CD pipeline.

Before you begin

Before you begin to create your login script, ensure that you have:

  • Read the introductory information about the zeuz API.

    See API introduction.

  • Read the summary of the zeuz base API authentication process, so you know what you need to set up.

    See API authentication.

  • Access to a Developer profile linked to your zeuz account.

    • You use either your Developer details or an API key to send API requests, depending on the endpoint’s authorization level.

      See Authorization for details.

    • You use a Developer profile to create an API key.

      If you don’t have access to a zeuz Developer profile linked to your zeuz account, create one.

      See Developers for details.

  • Generated an API key (depending on how you are accessing the API).

    You need to generate an API key if you want to call the zeuz base API from your game or from an external service (for example, to manage your payloads).

    We recommend that you generate a separate API key for each task you want to perform.

    See API keys for details.

  • Checked that the clock on your local development machine is set correctly.

    If it’s incorrect you might find that authentication fails with a request expired error.

    See the code in Step 4 - Call the auth_login endpoint for example error handling.

Once you have your Developer login details and/or your API key and API password, perform the following steps in your login script.

Step 1 - Generate a nonce and timestamp

Write a function that generates a nonce (number used once) and a timestamp. You will use this function in Step 3 - Create and encode a request-hash.

See Time handling for more information about zeuz timestamps.

Example snippet in C++:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <chrono>
#include <string>
#include <unistd.h>

// Generate a nonce of a specified length
std::string generate_nonce(const int len) {
   std::string tmp_s;
   static const char alphanum[] =
      "0123456789"
      "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
      "abcdefghijklmnopqrstuvwxyz";

   srand( (unsigned) time(NULL) * getpid());

   tmp_s.reserve(len);

   for (int i = 0; i < len; ++i) {
       tmp_s += alphanum[rand() % (sizeof(alphanum) - 1)];
   }

   return tmp_s;
}
// Generate a zeuz timestamp for the current time
// See doc.zeuz.io/docs/time-handling for more information
long zeuz_now() {
   auto now = std::chrono::system_clock::now();
   auto now_ms = std::chrono::time_point_cast<std::chrono::seconds>(now);
   auto epoch = now_ms.time_since_epoch();
   return (epoch.count() + 2208988800) * 1000 * 1000;
}

Step 2 - Create and encode a password-hash

Write a function that uses your zeuz Developer username and password, or your API key and API password, to generate a password-hash. Whether you use Developer or API credentials depends on the requirements of the API endpoints you plan to call. See Authorization for more information.

The function (generate_pwhash in the example snippet below) must do the following:

  1. Concatenate the word “zeuz” with your Developer username or API key, to create a Salt.

  2. Pass the Salt, with your Developer password or API password, to an Scrypt function to generate an Scrypt hash. The example below uses the libscrypt library.

  3. Encode the Scrypt hash using base64.

  4. Concatenate the letter “a” with the encoded Scrypt hash to create the final password-hash.

Example snippet in C++:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <libscrypt.h>

// Use your chosen library to perform base64 encoding
std::string base64_encode(unsigned char * value, unsigned int length);

// Generate a password-hash
std::string generate_pwhash(std::string login, std::string password) {
   std::string salt = "zeuz" + login;
   uint8_t hash[32] = { 0 }; // The output hash is 32 bits long

   // This example uses the libscrypt-dev library. To install it:
   // sudo apt-get install libscrypt-dev
   libscrypt_scrypt(
       reinterpret_cast<const uint8_t*>(&(password.c_str())[0]),
       password.length(),
       reinterpret_cast<const uint8_t*>(&(salt.c_str())[0]),
       salt.length(),
       1024,
       8,
       1,
       hash,
       32);

   return "a" + base64_encode((unsigned char *) hash, 32);
}

Step 3 - Create and encode a request-hash

Write a function to combine the nonce, timestamp and password-hash into a single hashed value called the request-hash, and then encode the request-hash using base64.

The following image summarises the flow, using the function names and variable names from the example code below:

Image: request_hash creation flow.

Image: request_hash creation flow.

You will use the function in Step 5 - Create a session key. In the example below the function is called zeuz_hash. We’ve included function declarations to clarify the arguments and return values.

Example snippet in C++:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// Hash the input string using the secure hash algorithm SHA3-256
void sha3_256_hash(const char * value, int length, unsigned char ** output, unsigned int * output_length);

// Encode the input string using base64
std::string base64_encode(unsigned char * value, unsigned int length);

// Hash the input string using the secure hash algorithm SHA3-256
// then encode it using base64 and return the value
std::string zeuz_hash(std::string value) {
   unsigned char * hash;
   unsigned int hash_length;
   sha3_256_hash(value.c_str(), value.length(), &hash, &hash_length);
   std::string base64_hash = base64_encode(hash, hash_length);
   return base64_hash;
}

// Generate a nonce of a specified length
auto nonce = generate_nonce(10);

// Generate a zeuz timestamp for the current time
// See doc.zeuz.io/docs/time-handling for more information
auto now = zeuz_now();

// Generate a password-hash
auto pwhash = generate_pwhash(login, password);

// Combine the nonce, timestamp and password-hash into a request-hash
auto request_hash = zeuz_hash(nonce + std::to_string(now) + pwhash);

Step 4 - Call the auth_login endpoint

Use the request-hash from the above step to log into zeuz using the auth_login API endpoint. You must post the login data in JSON format.

You must also supply the other properties auth_login requires. See auth_login in the API Reference for more details on the endpoint properties.

zeuz generated a password-hash value when you created your Developer profile and/or API key. zeuz uses this password-hash, together with the nonce and timestamp you supply in auth_login, to create a hashed value that is identical to your request-hash. If the two match, zeuz judges it to be a valid login. If they don’t, zeuz rejects the login request.

If the login is successful, zeuz sends some details to the function that performs the login, including the following:

  • Session ID: A unique value that identifies the session. You must send this in future requests.

    See API authentication for more information.

    Note: Future requests are API requests you perform after login, within the same logged in session.

  • Session nonce: A new random string for single use.

  • ValidThru: The date/time of the session expiry.

In your script, extract these values to use in future API requests.

Example snippet in C++:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
// Format your login data in JSON
Json::Value data;
Json::FastWriter writer;
data["Time"] = Json::Int64(time);
// Request-hash
data["Data"]["Hash"] = hash;
data["Data"]["IsApi"] = true;
data["Data"]["IsUser"] = false;
data["Data"]["Login"] = login;
// Nonce
data["Data"]["Nonce"] = nonce;
// Timestamp
data["Data"]["Time"] = Json::Int64(time);
auto json = writer.write(data);

// Send the data in a HTTP POST request body to the zeuz API 
// auth_login endpoint
auto response = post_request("https://zcp.zeuz.io/api/v1/auth_login", json);

// Parse the JSON response
Json::Reader reader;
Json::Value response_json;
if (!reader.parse(response, response_json)) {
// Throw an error if the parse fails
// Note: In production code, use a C++ exception instead
   throw std::string("could not parse response data ( " + response + ")");
}

// Check whether the error field is set.
auto error = response_json["Error"].asString();
if (!error.empty()) {
   // If the error starts with request_expired, 
   // the generated timestamp is too old
   if (error.rfind("request_expired", 0) == 0) {
       // Note: In production code you could retry the login,
       // or ensure the system clock is correct
       throw std::string("verify system clock or retry request");
   } else {
       // The error is unexpected. Authentication details might be 
       // incorrect. Note: In production code, use a C++ exception instead
       throw std::string("could not login (" + response + ")");
   }
}

// Extract the session ID, session nonce and date and date/time 
// of session expiry (ValidThru)
std::string session_id = response_json["Data"]["SessionId"].asString();
std::string session_nonce = response_json["Data"]["SessionNonce"].asString();
std::string valid_thru = response_json["Data"]["ValidThru"].asInt64();

Note: In rare cases, a session can expire earlier than the date/time specified in the ValidThru variable. To protect against this, monitor the response codes for your requests and reauthenticate if the session becomes invalidated early. See the Error handling page for more details.

Step 5 - Create a session key

Now you need to create a session key. To do this, use the function you created in step 3 (zeuz_hash in the example snippet) to combine the session nonce you received from zeuz in step 4 with your password-hash. The session key is valid for 24 hours.

The following image summarises the flow, using the function names and variable names from the example code. See steps 2 and 3 above for information on generate_pwhash.

Image: Session key creation flow.

Image: Session key creation flow.

Example snippet in C++:

1
2
// Combine the session nonce and password-hash into a session key
auto session_key = zeuz_hash(session_nonce + pwhash);

Next: Authenticate your API requests

Now that you’ve logged into zeuz, you can generate a sign-hash and attach it to your API requests.

To do this, you must generate a new nonce and a new timestamp and use them, together with the session key, to generate another hashed password called the sign-hash. You then use the sign-hash to authenticate API requests until the session key expires (24 hours from the time the session key’s creation time).

See Sign-hash generation for details and an example that generates a sign-hash to authenticate a followup API request.



2021-aug-09 Page updated with editorial review: added request_hash and session key creation flow images.

2021-may-12 Page added with editorial review.


Last edited on: October 13, 2021 (149a70bd)