Sitemap
Better Programming

Advice for programmers.

Follow publication

PHP: A Simple Example Using JSON Web Tokens With jQuery

6 min readOct 15, 2018
Image supplied by author

I recently wanted to learn more about JSON Web Tokens (JWTs) and how they worked. I found some server-side examples and some client-side examples, but really never found a single place that demonstrated the entire cycle. So I created my own and I’m sharing it here.

Historically, I’ve managed security using PHP session variables, which is a method that has a couple of downfalls. First, it requires some server-side management if you are load-balancing multiple web servers. You’ll likely need to implement a caching solution like Redis or Memcache and define a caching server to store the sessions. Second, on the client side, PHP stores a session cookie that could allow exposure of session variable information used in your authentication scheme.

JWTs solve this by using a token that is created on the server and contains specific information about the authenticating client that’s hashed and encoded. This token is then handed back to the client, which can use this token with future API requests and not require further authentication.

The JWT Breakdown

JWTs are built with three components: a header, the payload, and a signature.

The header contains information regarding which algorithm was used to hash the token. In our example, we’ll be using HMAC-SHA256, an algorithm that uses a secret key.

The payload (also called the claims of the token) contains data that’s stored inside of the token. In our example, we are going to store the user id of the authenticated user in the payload. Although we are only going to store one item in the payload, you can store as many claims as you want. Just keep in mind that you should consider performance when doing so and remember that the token is not intended as a vehicle for transferring data requests, but instead is merely a tool used in authentication of data requests.

In our example, the user id in the token can be used on the server as an index key to query information specific to the authenticated user in subsequent requests, without asking the user to identify themselves again — for example, navigating the user to a page displaying a list of their orders.

There are also some standard claims that can be included in the payload such as exp (expiration date and time) and nbf (not before date and time), which identifies the time on which the JWT will start to be accepted for processing. Our example will include the ability to include exp andnbf in your testing. You can check out the Wikipedia page for JWTs to read about the other standard fields.

The signature is a hashed representation of the header and payload. The header and payload are base64url-encoded respectively and then joined together with a period header.payload into a new variable. That variable is then hashed, in our case using the HS256 algorithm with a secret key, into a new variable which is then also base64url-encoded into the signature. The signature is appended to the header and payload variables with another period header.payload.signature into a final variable that is our token, which is passed back to the client.

And that’s how it works. There are lots of articles out there that also explain this, but at least we’ve set the stage for our example. Let’s get into it.

Example

My example uses three files that can be freely downloaded from my repository.

index.html

This is a simple landing page that provides buttons that demonstrate different examples of interacting with the app_client.php file on the server.

  • Good Login — submits a POST with a username of john.doe and a password of foobar. If authentication is successful, a token is returned. The client can decide how they want to store the token for future use. In our case, we’re going to store it in the browser localStorage.
  • Bad Login — submits a POST with a username of john.doe and an invalid password of foobarfoobar. This will cause the app_client to reject the authentication attempt with an error and no token. Upon receiving the error, the client clears any existing token, and the user will be required to get a new token using the Good Login button before any further tests will work.
  • Test if Logged In — will issue a GET using the token stored in localStorage. If it is successful, the app_client will return back the user id we’ve stored in the payload of the token.
  • Logout and Clear Token — simply clears any existing token from localStorage and forces the user to get a new token with the Good Login button before any further tests will work.

app_client.php

This server-side PHP file accepts the method requests from index and processes them accordingly.

POST requests accept the username and password fields and validates them, returning an error if they are not valid. If they are valid, then the jwt.php file is included (explained in a bit) to handle all token functions. Then some variables are created that are used in the JWT creation.

The first is a user id that is used as our first claim in the payload:

$userId = 'USER123456';

This simply demonstrates that we can put whatever data we want in a claim. In this example, we’re including a useful bit of information that we can use on the server later for such things as querying data specific to this user without requiring further authentication or selections.

The next two variables are used for controlling the life of the token:

$nbf = strtotime('2021-01-01 00:00:01');

$exp = strtotime('2021-01-01 00:00:01');

The $nbf and $exp variables correspond to their standard field counterparts in the payload. In the example above, a token generated with a nbf (not before) date set to January 1, 2021, at 12:01 a.m. will not allow validation prior to that date. You can test this in your development environment by uncommenting that line and setting it to an appropriate date and time for testing.

In the above example, a token generated with an exp (expiration) date set to January 1, 2021, at 12:01 a.m. will only work up until that date and time, at which point it will expire and no longer be valid. You can test this in your development environment by uncommenting this line and setting it to an appropriate date and time.

If either of these two date/time variables is violated, the app_client will return an exception error toindex.

The final variable is a server key (in this case a GUID) that we’ll use for our hashing algorithm in the signature. In our example, only the server knows the key; therefore, the tokens that are created can only be decoded by the server:

$serverKey = '5f2b5cdbe5194f10b3241568fe4e2b24';

The next block of code packages up our claim variables into a payload array and then passes that along with the server key to jwt.php for encoding into a token:

// create a token
$payloadArray = array();
$payloadArray['userId'] = $userId;
if (isset($nbf)) {$payloadArray['nbf'] = $nbf;}
if (isset($exp)) {$payloadArray['exp'] = $exp;}
$token = JWT::encode($payloadArray, $serverKey);

// return to caller
$returnArray = array('token' => $token);
$jsonEncodedReturnArray = json_encode($returnArray, JSON_PRETTY_PRINT);
echo $jsonEncodedReturnArray;

The resulting token is then packaged up into a JSON encoded return array and returned back to index.

jwt.php

This class library is based on the original Firebase/JWT source code written by Neuman Vong and Anant Narayanan found here: https://github.com/firebase/php-jwt.

To facilitate my simple example, I’ve removed the need for composer dependencies, namespace references, and specialized error exceptions. All other functionality and interfaces remain the same. Once you’ve grasped the concepts, I’d encourage you to install their JWT class library as that will provide you with ongoing updates to the library.

The jwt.php class library provides all of the functionality for encoding and decoding JSON Web Tokens, including processing the payload standard fields.

Try It Out!

You can download these three files from GitHub. Place them all in the same folder in your development environment and try them out. The code is intentionally written for clarity and ease of stepping through with a debugger.

I hope this helps you gain an understanding of how JSON Web Tokens can be used in your authentication stack!

Casey McMullen
Casey McMullen

Written by Casey McMullen

Co-Founder & CEO at Another™ : Web Developer : Tech Geek : Guitar Player

Write a response