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.
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
And why is the “alg”: “HS256” key in the header if this information is not used in the body of generate_jwt?
thanks bro <3 god bless you
how to set expiry time in jwt. in above article no use any third party library