Example: C++
The following code is an example of how to generate access tokens in C++.
/*
* Vivox Token Generation Example - C++
* Note: This example uses C++11, and is written to not use external libraries to demonstrate the token generation process.
* However, because HMACSHA256 is required, this example uses OpenSSL 1.1.0+.
*
*/
#include <openssl/sha.h>
#include <openssl/evp.h>
#include <openssl/hmac.h>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <string>
using namespace std;
typedef unsigned char uchar;
static const string b = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_+/";
/*
* You can use Base64URL encoding or Base64 and URL encoding libraries in place of this implementation
* Note: Any trailing ='s must be removed from the encoded string.
*/
static string base64_encode(const string &in)
{
string out;
int val = 0, valb = -6;
for (const char c : in) {
val = (val << 8) + static_cast<unsigned char>(c);
valb += 8;
while (valb >= 0) {
out.push_back(b[(val >> valb) & 0x3F]);
valb -= 6;
}
}
if (valb >- 6) out.push_back(b[((val << 8) >> (valb + 8))& 0x3F]);
return out;
}
#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || defined(LIBRESSL_VERSION_NUMBER)
static HMAC_CTX *HMAC_CTX_new(void)
{
HMAC_CTX *ctx = static_cast<HMAC_CTX *>(OPENSSL_malloc(sizeof(*ctx)));
if (ctx != nullptr) {
HMAC_CTX_init(ctx);
}
return ctx;
}
static void HMAC_CTX_free(HMAC_CTX *ctx)
{
if (ctx != nullptr) {
HMAC_CTX_cleanup(ctx);
OPENSSL_free(ctx);
}
}
#endif
/*
* Uses OpenSSL 1.1.0+ to encode data with a secret using HMAC SHA-256
*/
string hmac(string key, string msg)
{
unsigned char hash[32];
HMAC_CTX *hmac = HMAC_CTX_new();
HMAC_Init_ex(hmac, &key[0], static_cast<int>(key.length()), EVP_sha256(), nullptr);
HMAC_Update(hmac, reinterpret_cast<const unsigned char *>(&msg[0]), msg.length());
unsigned int len = 32;
HMAC_Final(hmac, hash, &len);
HMAC_CTX_free(hmac);
stringstream ss;
ss << setfill('0');
for (unsigned int i = 0; i < len; i++) {
ss << hash[i];
}
return ss.str();
}
static string vx_generate_token(const string &key, const string &issuer, int exp, const string &vxa, int vxi, const string &f, const string &t)
{
// Header is static - base64url encoded {}
string header = base64_encode("{}"); // Can also be defined as a constant "e30"
// Create payload and base64 encode
stringstream ss;
ss << "{ \"iss\": \"" << issuer << "\",";
ss << "\"exp\": " << exp << ",";
ss << "\"vxa\": \"" << vxa << "\",";
ss << "\"vxi\": " << vxi << ",";
ss << "\"t\": \"" << t << "\",";
ss << "\"f\": \"" << f << "\" }";
string payload = base64_encode(ss.str());
// Join segments to prepare for signing
string to_sign = header + "." + payload;
// Sign token with key and HMACSHA256, then base64 encode
string signed_payload = base64_encode(hmac(key, to_sign));
// Combine header and payload with signature
return to_sign + "." + signed_payload;
}
int main()
{
string token = vx_generate_token("secret", "issuer", 1559359105, "join", 123456, "sip:.username.@domain.vivox.com", "sip:confctl-g-channelname@domain.vivox.com");
cout << token << endl;
return 0;
}