How To Generate And Validate JWT Using PHP Without Using Third Party API

Introduction

In this tutorial you will see how to generate and validate JWT (JSON Web Token) using PHP programming language without using any third-party library or plugin. I would not explain here what is JWT and why JWT is used but you can find wonderful documentation in its own JWT Website.

This example of generating and validating JWT does not use any third-party library and you may tweak the source code according to your needs. I will set the expiry time during the JWT generation for security reason to avoid an indefinite validity of the generated token. And once the token gets expired, a user must get a new token. For this example, I will keep the validity time of the generated token for 60 seconds.

To generate JWT you need mainly header, payload and secret. Next you create a signature from the encoded header, the encoded payload, a secret, the algorithm specified in the header.

generate and validate jwt in php

Typical cryptographic algorithms used are HMAC with SHA-256 (HS256) and RSA signature with SHA-256 (RS256).

Related Posts:

JWT Header

The header typically consists of two parts: the type of the token, which is JWT, and the signing algorithm being used, such as HMAC SHA256 or RSA.

For example:

{
  "alg": "HS256",
  "typ": "JWT"
}

Then, this JSON is Base64Url encoded to form the first part of the JWT.

JWT Payload

The second part of the token is the payload, which contains the claims. Claims are statements about an entity (typically, the user) and additional data. There are three types of claims: registered, public, and private claims. For more information on each type you can read https://jwt.io/introduction/.

An example payload could be:

{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true
}

The payload is then Base64Url encoded to form the second part of the JSON Web Token.

JWT Signature

For example if you want to use the HMAC SHA256 algorithm, the signature will be created in the following way:

HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)

The signature is used to verify the message wasn’t changed along the way, and, in the case of tokens signed with a private key, it can also verify that the sender of the JWT is who it says it is.

Now let’s see how to generate and validate JWT using PHP language.

Prerequisites

PHP 7.3.5 – 7.4.23

Generate JWT

The output of the generated JWT is three Base64-URL strings separated by dots.

function generate_jwt($headers, $payload, $secret = 'secret') {
	$headers_encoded = base64url_encode(json_encode($headers));
	
	$payload_encoded = base64url_encode(json_encode($payload));
	
	$signature = hash_hmac('SHA256', "$headers_encoded.$payload_encoded", $secret, true);
	$signature_encoded = base64url_encode($signature);
	
	$jwt = "$headers_encoded.$payload_encoded.$signature_encoded";
	
	return $jwt;
}

Here is the Base64-URL encoded function definition:

function base64url_encode($str) {
    return rtrim(strtr(base64_encode($str), '+/', '-_'), '=');
}

Following is an example of how to generate JWT:

$headers = array('alg'=>'HS256','typ'=>'JWT');
$payload = array('sub'=>'1234567890','name'=>'John Doe', 'admin'=>true, 'exp'=>(time() + 60));

$jwt = generate_jwt($headers, $payload);

echo $jwt;

The output of the above code snippets is:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjEyMzQ1Njc4OTAiLCJuYW1lIjoiSm9obiBEb2UiLCJhZG1pbiI6dHJ1ZSwiZXhwIjoxNTgyNjE2MDA1fQ.umEYVDP_kZJGCI3tkU9dmq7CIumEU8Zvftc-klp-334

Validate JWT

Now you got the JWT generated in the above step. It’s time to verify whether you get the same header and payload from the JWT. Hence you will need to validate your generated JWT.

function is_jwt_valid($jwt, $secret = 'secret') {
	// split the jwt
	$tokenParts = explode('.', $jwt);
	$header = base64_decode($tokenParts[0]);
	$payload = base64_decode($tokenParts[1]);
	$signature_provided = $tokenParts[2];

	// check the expiration time - note this will cause an error if there is no 'exp' claim in the jwt
	$expiration = json_decode($payload)->exp;
	$is_token_expired = ($expiration - time()) < 0;

	// build a signature based on the header and payload using the secret
	$base64_url_header = base64url_encode($header);
	$base64_url_payload = base64url_encode($payload);
	$signature = hash_hmac('SHA256', $base64_url_header . "." . $base64_url_payload, $secret, true);
	$base64_url_signature = base64url_encode($signature);

	// verify it matches the signature provided in the jwt
	$is_signature_valid = ($base64_url_signature === $signature_provided);
	
	if ($is_token_expired || !$is_signature_valid) {
		return FALSE;
	} else {
		return TRUE;
	}
}

Following is an example of validating generated JWT:

$is_jwt_valid = is_jwt_valid('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjEyMzQ1Njc4OTAiLCJuYW1lIjoiSm9obiBEb2UiLCJhZG1pbiI6dHJ1ZSwiZXhwIjoxNTgyNjE2MDA1fQ.umEYVDP_kZJGCI3tkU9dmq7CIumEU8Zvftc-klp-334');

echo nl2br("\n");

if($is_jwt_valid === TRUE) {
	echo 'JWT is valid';
} else {
	echo 'JWT is invalid';
}

Testing JWT Application

Generate JWT by executing the file jwt.php using CLI (command line interface):

\php-jwt-generation-validation>php jwt.php

The generated JWT is given below:

eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImV4cCI6MTYzMjQ2NTM2OX0.727eMu6rKHXJX2PgiqbdrkPqp0-eRrvY2NfnxI6TDcY

Now copy the above JWT in the file jwt_valid.php:

…
$is_jwt_valid = is_jwt_valid('eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImV4cCI6MTYzMjQ2NTM2OX0.727eMu6rKHXJX2PgiqbdrkPqp0-eRrvY2NfnxI6TDcY');
…

Finally execute the jwt_valid.php file using CLI:

\php-jwt-generation-validation>php jwt_valid.php

You will see the following output:

JWT is valid

The JWT is valid for 60 seconds or 1 minute. Now after 1 minute if you check the validity of the above JWT, you will get invalid.

\php-jwt-generation-validation>php jwt_valid.php

Output: JWT is invalid

Source Code

Download

3 thoughts on “How To Generate And Validate JWT Using PHP Without Using Third Party API

  1. And why is the “alg”: “HS256” key in the header if this information is not used in the body of generate_jwt?

Leave a Reply

Your email address will not be published. Required fields are marked *