Generating Tokens without Server Side SDK

During AngelHack, Alexander Ramirez came up to me with a puzzle. “How do I generate sessions and tokens?” He asked. Normally, I would have told him to use one of our server side SDKs, but he was building a browser plugin with video chat and wanted to use our REST API instead. Getting the SessionId is easy, it’s a simple POST request. However, generating token is not so straightforward because it is generated algorithmically. This tutorial will show you how to generate a token, and examples used here will be written in JavaScript.

Tokens are base64 encoded string with the following data fields: partner_id, sig, session_id, create_time, expire_time, role, connection_data, and nonce.

First, let’s generate the simple fields.

session_id can be created by sending a post request to our server.

Create_time is stored in seconds so we need to write Date.now()/1000

expire_time can be set set to 24 hours (86400 seconds) from today, so it’s value is create_time + 86400

role if I want my user to be able to record the session and force others to disconnect, I would put ‘moderator’ here

connection_data We can put in the user name for data, which in this case can just be “bob”

nonce is a random number, Math.floor( Math.random()*99999 )

The trickest value to generate is the sig key, which is used to verify these token values. To generate this encrypted signature, we need to use Keyed-hash message authentication codes. Fortunately, there is a javascript library called Crypto that let’s us do just that.

We will use progressive HMAC Hashing, so we will first need to generate a HMAC object with our secret, pass in our token values, and then finalize the HMAC.

var hmac = CryptoJS.algo.HMAC.create(CryptoJS.algo.SHA1, "Secret Passphrase");
hmac.update("session_id="+sessionId+"&create_time=...");
var hash = hmac.finalize();

If you now print out this sig as a string, it should look something like this: 58ceea3adfd277c02545e3eaef23dfcf94496803

Now time to put all these values together into one string:

"partner_id=...&sig=...:session_id=...&create_time=...&expire_time=...

Base64 encode this new string and then add the “T1==” to the beginning of the encoded string. You can now use this token to authenticate yourself to that specific session.

Here’s the full code

With that said, please be aware that you should never expose your secret in your client side code due to security concerns.

Thanks for reading,

Song

  • Nick

    Thanks, Song. This is really helpful. One question that I could probably figure out myself but thought I would just ask on here in case others are looking for the answer: How is this done using the iOS SDK? I would think that generating the sig key would be done differently if nothing else. One other thing that could be useful is a tutorial for integrating with mobile backend solutions like Parse, which are becoming increasingly common.

  • Pingback: TokBox tout de suite - Elitist

  • Gabriel Díaz

    In your text you have:

    var hmac = CryptoJS.algo.HMAC.create(CryptoJS.algo.SHA256, “Secret Passphrase”);

    but in your code you have:

    var hmac = CryptoJS.algo.HMAC.create(CryptoJS.algo.SHA1, secret);

    So which one is the correct? i guess it’s SHA1, but just in case… ;)

    • http://aoberoi.me Ankur Oberoi

      Great catch! You are correct and it is supposed to be SHA1. Thank you.

  • Adam Dennis

    I feel as though this would be a very common question, and should be linked to from this page: http://tokbox.com/opentok/libraries/client/ios/

    • http://songz.me/ Song Zheng

      Hey Adam! You are correct! Will file this as a task on Jira to add it into our docs. Thanks for pointing this out!

      • Adam Dennis

        Thanks for the acknowledgement :)

    • http://aoberoi.me Ankur Oberoi

      @disqus_ZAfulnwsbN:disqus just wanted you to know that this is not meant to be done anywhere than locally during development as a shortcut. embedding your API Secret on a webpage that is readable to the world can cause others to take control of your account and make you responsible to foot the bill.

      • Adam Dennis

        Hey Ankur,

        Thanks for the reply.
        You’re very correct in this, and it was just for testing… It would be crazy-bad for others to
        I’ve since decided to use your NodeJS library from github, and am generating a new session and token for each new video chat I start.

        Best,
        Adam

  • ermannofaccio

    però…

  • http://www.darraghduffy.ie Darragh Duffy

    this is a very similar algorithm to oAuth; can I assume this algorithm is still used for the token generation; and is their an expectation this algorithm will change. I basically have to write a server side version for this because we cant use one of the existing libs easily.

    • http://aoberoi.me Ankur Oberoi

      The algorithm remains the same today. That isn’t to say that it wouldn’t change in the future, but that would be announced well ahead of any need to migrate those changes and we would support the older scheme as a deprecated technique for a reasonable amount of time before cutting support. You’re very welcome to migrate it to another platform or language.

      Out of curiosity, what is so challenging about incorporating one of the existing Server SDKs? Is there none available in the language or technology stack that you prefer?

      • http://www.darraghduffy.ie Darragh Duffy

        thanks Ankur; our architect using OHS (Oracle HTTP Server) with mod_PLSQL; this is basically Apache with an Oracle module mod_plsql plugged in. Allowing us to use Oracle’s PLSQL as the server side language. I have written oAuth libs in mod_plsql and very familar with HMAC & hashing in general. thanks for the clarification on the algorithm

        What is strange I used the TOXBOX dashbaord to produce session and tokens for test purposes the base 64 encoded signature was

        cGFydG5lcl9pZD00NTA1MjM3MiZzaWc9NjkyY2E4Njc0MDBiMjk2MjhmODRlNjM4M2NjNmQ1YjM0ZjliZDY3OTpyb2xlPXB1Ymxpc2hlciZzZXNzaW9uX2lkPTJfTVg0ME5UQTFNak0zTW41LU1UUXhORGc0T0RFME1EazJOMzR2VkZkVlYxbGlZemc0Tm1OTmVHZHJVeXR4VFVOcFRFeC1mZyZjcmVhdGVfdGltZT0xNDE0ODg4MTUzJm5vbmNlPTAuMjM4MDI0MzY3MzEwNDc1MjcmZXhwaXJlX3RpbWU9MTQxNDk3MzIwMg==

        this tranlsates to

        partner_id=45052372&sig=692ca867400b29628f84e6383cc6d5b34f9bd679:role=publisher&session_id=2_MX40NTA1MjM3Mn5-MTQxNDg4ODE0MDk2N34vVFdVV1liYzg4NmNNeGdrUytxTUNpTEx-fg&create_time=1414888153&nonce=0.23802436731047527&expire_time=1414973202

        I found it strange that the :role=publisher appears directly after the HASH sig; this was not in the algorithm. Additionally based on the following details; the HASH does not add up as I expect i.e.

        using the following secret along with the values in the decoded base 64 I should be able to produce the same hash.

        a8f68b0e44a561fd6a00da39060b114f9fa697a6

        using the algorithm above the string to hash would be

        session_id=2_MX40NTA1MjM3Mn5-MTQxNDg4ODE0MDk2N34vVFdVV1liYzg4NmNNeGdrUytxTUNpTEx-fg&create_time=1414888153&expire_time=1414973202&role=publisher&nonce=0.23802436731047527

        connection_data is not included becuase having read the source code connection_data is not included if the data is null.

        This prioduces the following HASH

        bf46d4bb1960ea79d2437ef3eacd4df4ca292a7b

        which does not match the value in base 64 decode. so two questions

        1. why is the algorithm not include :role=publisher

        2. with the known values above why is the standard HMAC with the given secret not producing the same HASH your server side SDK produces when using the TOXBOX dashboard?

        I have also this dopcumented in the forum in toxbox

        https://forums.tokbox.com/supported-server-api/creating-a-token-from-rest-api-t44260

        thanks for reviewing this

        • http://www.darraghduffy.ie Darragh Duffy

          hi ankur, any chance you have reviewed the above?

          • http://aoberoi.me Ankur Oberoi

            Hey Darragh, sorry about my late response, the email notification got burried in my inbox.

            1. The “:” that preceeds “role=publisher” is not specific to the “role” attribute; its a separator between what we consider the “header” of the token’s data and the much more flexible “body”. The header is of the form “partner_id={APIKEY}&sig={hash(body)}”.

            2. There are attributes in the body that are optional and when they are left out would be supplied with a default. My recommendation would be to explicitly set them in your tokens so that your implementation isn’t fragile enough to break if our defaults change. The list of attributes in the body at this moment are: “session_id”, “create_time”, “expire_time”, “role”, “connection_data”, “nonce”. The Dashboard may choose to leave some of the attributes out if they are just set to the default, which would change the hash that is used as the “sig” in the header.

            The canonical source for the algorithm would be our Server SDK packages. As you’ve probably noticed we don’t have anything specific for PLSQL, so I’m glad you’re putting in the effort to port the implementation. But if there is a language in which you are comfortable referencing from the six that we currently have SDKs in (PHP, Java, Python, Ruby, JavaScript, and C#), then referring to those implementations on our GitHub page (https://github.com/opentok) could be helpful.

            I wanted to mention that if the implementation you have is reusable and if you wouldn’t mind sharing it, we would greatly appreciate you publishing it. We could then share that with other developers who face the same challenge. Perhaps putting that piece on GitHub would be something you’re interested in?

          • http://www.darraghduffy.ie Darragh Duffy

            no problems Ankur. Ok, I actually found out what the issue was and now have the session and token generation working, I have certified this against http://digitaltsai.com/ot/examples/credChecker.php

            However, you guys have a small bug that you are not aware of. In most implementations to generate a HASH or HMAC e.g. .net, php, JAVA and even the Crypto lib in JS produces the hash result in lower case characters. The result of a HASH is not case sensitive, while the values input into a HASH are case sensitive. When in Oracle I use the has function it outputs the results in upper case; so basically the issue I was encountering is the sig in my case was all upper case which is not wrong, the HASH result was still the same as your system was producing. I suggest to make your server side more robust that you would test for uppercase signatures or at least indicate in the algorithm that the siganture must be lower case. As you are base 64 encoding the dataString this is a little more tricky.

            on line 30 if you did

            hash = hmac.finalize().toUpperCase();
            instead of
            hash = hmac.finalize();

            you will see the same issue I was encountering.

            Anyway, I have this working now in Oracle PLSQL where I force lower case on the signature.

            And Yes happy to share the ported solution; send on the GIT repo and I will commit / push.
            I just need to make it production ready and comment the code