Create Auth Tokens with PHP

By  on  

Working with OAuth and similar authentication protocols requires the use of temporary tokens which represent unique handshakes between multiple web services.  These tokens must be unique, securely stored, and the longer, the better.

Since I've been out of the PHP game for a while, I was researching how to create such tokens without additional libraries.  The following snippet does the trick:

// bin2hex(random_bytes($length))
$token = bin2hex(random_bytes(64));

/*
  Examples:

  39e9289a5b8328ecc4286da11076748716c41ec7fb94839a689f7dac5cdf5ba8bdc9a9acdc95b95245f80a00d58c9575c203ceb541507cce40dd5a96e9399f4a
  1c46538c712e9b5bf0fe43d692147004f617b494d004e29daaf33e4528f253db5d911a690856f0b77cfa98103c8231bffff869f179125d17d28e52bfadb9f205
  ...
*/

If you aren't using PHP7 or above, you can fallback to the following:

$token = bin2hex(openssl_random_pseudo_bytes(64));

Having the backing of OpenSSL for token generation gives confidence that the token will be unique.  Of course you can also do a storage check to ensure the token isn't already in use, but if you use a length of 64 or larger, the chances you repeat a token are incredibly slim!

Recent Features

  • By
    39 Shirts – Leaving Mozilla

    In 2001 I had just graduated from a small town high school and headed off to a small town college. I found myself in the quaint computer lab where the substandard computers featured two browsers: Internet Explorer and Mozilla. It was this lab where I fell...

  • By
    6 Things You Didn’t Know About Firefox OS

    Firefox OS is all over the tech news and for good reason:  Mozilla's finally given web developers the platform that they need to create apps the way they've been creating them for years -- with CSS, HTML, and JavaScript.  Firefox OS has been rapidly improving...

Incredible Demos

  • By
    AJAX For Evil:  Spyjax with jQuery

    Last year I wrote a popular post titled AJAX For Evil: Spyjax when I described a technique called "Spyjax": Spyjax, as I know it, is taking information from the user's computer for your own use — specifically their browsing habits. By using CSS and JavaScript, I...

  • By
    Cross Browser CSS Box Shadows

    Box shadows have been used on the web for quite a while, but they weren't created with CSS -- we needed to utilize some Photoshop game to create them.  For someone with no design talent, a.k.a me, the need to use Photoshop sucked.  Just because we...

Discussion

  1. Thanks for sharing!

  2. Valtteri

    I’ve used this, because it’s produces a shorter string:

    $token = base64_encode(random_bytes(64));
    
    // Example:
    // yak91pYnDWkaDPEjGAOgGcdTA4ybHF+R+5KVcvgfuoAJz3QMmaxJfBYIkKT9zpSDRE6jfHMW9jahsw1b/aMXtw==
    

    Usually I replace + and / with - and _, so it doesn’t need encoding anywhere:

    $token = strtr($token, '+/', '-_');
    
  3. A word of advice: don’t use openssl_random_pseudo_bytes() as a fallback for random_bytes() in PHP 5.x, use the random_compat library instead: https://github.com/paragonie/random_compat.

  4. Thanks for the trick. How’s the random_compat compared to openssl_random_pseudo_bytes()

  5. Sound is great!!!

    It can be done either way, and values in a GET request aren’t really any more visible than values in a POST request. If anybody can “see” (i.e. intercept) the request, he can see everything you’re sending. In the end an HTTP request is just a bunch of HTTP headers possibly followed by a body. The URL is send in the first GET /foo/bar HTTP/1.1 line, other values are just send in different, following lines.

    So it’s up to you where you expect your authentication token to be send. You can require it to be a query parameter that is appended to every request:

    GET /foo/bar?user=123456&token=abcde…

    To really use the HTTP protocol as intended though, you should use the Authorization HTTP header:

    Authorization: MyScheme 123456:abcde…
    The content of this header is entirely up to you. It usually specifies an authorization method like Basic, followed by whatever you want to require for authentication. This can simply be the username and password, a hash of them, an opaque token the client has obtained at some point or anything else really.

    I’d recommend a token system or a request signing system, with the latter being very much preferred. In a request signing system, the client has to obtain a token from you. It then sends a hash of this token and certain characteristics of the request to authenticate the request, e.g. sha1(Token + Timestamp + Request URL + Request Body). Your server can validate this without the client having to send the token in plain text on each request.

  6. Following is the code I tried on my own but I don’t know whether it’s right or wrong. Is my approach correct or wrong. Please someone analyse it and let me know your feedback on it.

    To create a token i use this function which takes as parameters, the user’s data

    define('SECRET_KEY', "fakesecretkey");
    
    function createToken($data)
    {
        /* Create a part of token using secretKey and other stuff */
        $tokenGeneric = SECRET_KEY.$_SERVER["SERVER_NAME"]; // It can be 'stronger' of course
    
        /* Encoding token */
        $token = hash('sha256', $tokenGeneric.$data);
    
        return array('token' => $token, 'userData' => $data);
    }
    

Wrap your code in <pre class="{language}"></pre> tags, link to a GitHub gist, JSFiddle fiddle, or CodePen pen to embed!