PHP Authorization with JWT (JSON Web Tokens) – SitePoint

There was a time when the only way to authenticate yourself with an application was by providing your credentials (usually a username or email address and a password) and a session was then used to maintain user state until the user logged out. A little while later, we started using authentication APIs. And in yet more recent times, JWTs, or JSON Web Tokens, have been increasingly used as another way to authenticate requests to a server.
In this article, you’ll learn what JWTs are and how to use them with PHP to make authenticated user requests.
JWTs versus Sessions
But first, why are sessions not such a good thing? Well, there are three key reasons:
Data is stored in plain text on the server.Even though the data is usually not stored in a public folder, anyone with sufficient access to the server can read the contents of session files.
They involve filesystem read/write requests.Every time a session starts or its data is modified, the server needs to update the session file. The same goes for every time the application sends a session cookie. If you have a large number of users, you can end up with a slow server unless you use alternative session storage options, such as Memcached and Redis.
Distributed/Clustered applications.Since session files are, by default, stored on the file system, it’s hard to have a distributed or clustered infrastructure for high availability applications — ones that require the use of technologies such as load balancers and clustered servers. Other storage media and special configurations have to be implemented — and be done so in full awareness of their implications.
Now, let’s start learning about JWTs. The JSON Web Token specification (RFC 7519) was first published on December 28, 2010, and was most recently updated in May 2015.
JWTs have many advantages over API keys, including:
API keys are random strings, whereas JWTs contain information and metadata. This information and metadata can describe a wide range of things, such as a user’s identity, authorization data, and the validity of the token within a time frame or in relation to a domain.
JWTs don’t require a centralized issuing or revoking authority.
JWTs are OAUTH2 compatible.
JWT data can be inspected.
JWTs have expiration controls.
JWTs are intended for space-constrained environments, such as HTTP Authorization headers.
Data is transmitted in JavaScript Object Notation format (JSON).
JWTs are represented using Base64url encoding
What Does a JWT Look Like?
Here is a sample JWT:

At first glance, it appears that the string is just random groups of characters concatenated with a period or dot character. As such, it may not seem very different from an API key. However, if you look more closely, there are three separate strings.

The first string is the JWT header. It’s a Base64, URL-encoded JSON string. It specifies which cryptographic algorithm was used to generate the signature, and the token’s type, which is always set to JWT. The algorithm can be either symmetric or asymmetric.
A symmetric algorithm uses a single key to both create and verify the token. The key is shared between the creator of the JWT and the consumer of it. It’s essential that you make sure only the creator and consumer knows the secret. Otherwise, anyone can create a valid token.
An asymmetric algorithm uses a private key to sign the token and a public key to verify it. These algorithms should be used when a shared secret is impractical or other parties only need to verify the integrity of the token.
The JWT’s Payload
The second string is the JWT’s payload. It’s also a Base64, URL-encoded JSON string. It contains some standard fields, which are referred to as “claims”. There are three types of claims: registered, public, and private.
Registered claims are predefined. You can find a list of them in the JWT’s RFC. Here are some commonly used ones:
iat: the timestamp of token issuing.
key: a unique string, which could be used to validate a token, but goes against not having a centralized issuer authority.
iss: a string containing the name or identifier of the issuer. Can be a domain name and can be used to discard tokens from other applications.
nbf: a timestamp of when the token should start being considered valid. Should be equal to or greater than iat.
exp: a timestamp of when the token should cease to be valid. Should be greater than iat and nbf.
Public claims can be defined as you see fit. However, they can’t be the same as registered claims, or claims of already existing public claims. You can create private claims at will. They’re only for use between two parties: a producer and a consumer.
The JWT’s Signature
The JWT’s signature is a cryptographic mechanism designed to secure the JWT’s data with a digital signature unique to the contents of the token. The signature ensures the JWT’s integrity so that consumers can verify it hasn’t been tampered with by a malicious actor.
The JWT’s signature is a combination of three things:
the JWT’s header
the JWT’s payload
a secret value
These three are digitally signed (not encrypted) using the algorithm specified in the JWT’s header. If we decode the example above, we’ll have the following JSON strings:
The JWT’s Header
“alg”: “HS256”,
“typ”: “JWT”

The JWT’s Data
“iat”: 1416929109,
“jti”: “aa7f8d0a95c”,
“scopes”: [

Try out for yourself, where you can play around with encoding and decoding your own JWTs.
Let’s Use JWTs in a PHP-based Application
Now that you’ve learned what JWTs are, it’s now time to learn how to use them in a PHP app. Before we dive in, feel free to clone the code for this article, or follow along and create it as we go.
There are many ways that you can approach integrating JWTs, but here’s how we’re going to do it.
All requests to the application, except for the login and logout page, need to be authenticated via a JWT. If a user makes a request without a JWT, they’ll be redirected to the login page.
After a user fills out and submits the login form, the form will be submitted via JavaScript to the login endpoint, authenticate.php, in our application. The endpoint will then extract the credentials (a username and password) from the request and check if they’re valid.
If they are, it will generate a JWT and send it back to the client. When the client receives a JWT, it will store it and use it with every future request to the application.
For a simplistic scenario, there’ll only be one resource the user can request — a PHP file aptly named resource.php. It won’t do much, just returning a string, containing the current timestamp at the time of the request.
There’s couple of ways to use JWTs when making requests. In our application, the JWT will be sent in the Bearer authorization header.
If you’re not familiar with Bearer Authorization, it’s a form of HTTP authentication, where a token (such as a JWT) is sent in a request header. The server can inspect the token and determine if access should be given to the “bearer” of the token.
Here’s an example of the header:
Authorization: Bearer ab0dde18155a43ee83edba4a4542b973

For each request received by our application, PHP will attempt to extract the token from the Bearer header. If it’s present, it’s then validated. If it’s valid, the user will see the normal response for that request. If the JWT is invalid, however, the user won’t be allowed to access the resource.
Please note that JWT was not designed to substitute session cookies.
To begin with, we need to have PHP and Composer installed on our systems.
In the project’s root, run composer install. This will pull in Firebase PHP-JWT, a third-party library that simplifies working with JWTs, as well as laminas-config, designed to simplify access to configuration data within applications
The Login Form

With the library installed, let’s step through the login code in authenticate.php. We first do the usual setup, ensuring that the Composer-generated autoloader is available.
modify(‘+6 minutes’)->getTimestamp();
$serverName = “”;
$username = “username”;

$data = [
‘iat’ => $issuedAt->getTimestamp(),
‘iss’ => $serverName,
‘nbf’ => $issuedAt->getTimestamp(),
‘exp’ => $expire,
‘userName’ => $username,

With the payload data ready to go, we next use php-jwt’s static encode method to create the JWT.
The method:
transforms the array to JSON
produce the headers
signs the payload
encodes the final string
It takes three parameters:
the payload information
the secret key
the algorithm to use to sign the token
By calling echo on the result of the function, the generated token is returned:

const res = await fetch(‘/authenticate.php’, {
method: ‘POST’,
headers: {
‘Content-type’: ‘application/x-www-form-urlencoded; charset=UTF-8’
body: JSON.stringify({
username: form.inputEmail.value,
password: form.inputPassword.value

if (res.status >= 200 && res.status <= 299) { const jwt = await res.text(); store.setJWT(jwt); = 'none'; = 'block'; } else { console.log(res.status, res.statusText); } }); Using the JWT When clicking on the “Get current timestamp” button, a GET request is made to resource.php, which sets the JWT received after authentication in the Authorization header. btnGetResource.addEventListener('click', async (e) => {
const res = await fetch(‘/resource.php’, {
headers: {
‘Authorization’: `Bearer ${store.JWT}`
const timeStamp = await res.text();

When we click the button, a request similar to the following is made:
GET /resource.php HTTP/1.1
Connection: keep-alive
Accept: */*
X-Requested-With: XMLHttpRequest
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE0MjU1ODg4MjEsImp0aSI6IjU0ZjhjMjU1NWQyMjMiLCJpc3MiOiJzcC1qd3Qtc2ltcGxlLXRlY25vbTFrMy5jOS5pbyIsIm5iZiI6MTQyNTU4ODgyMSwiZXhwIjoxNDI1NTkyNDIxLCJkYXRhIjp7InVzZXJJZCI6IjEiLCJ1c2VyTmFtZSI6ImFkbWluIn19.HVYBe9xvPD8qt0wh7rXI8bmRJsQavJ8Qs29yfVbY-A0

Assuming that the JWT is valid, we’d see the resource, after which the response is written to the console.
Validating the JWT
Finally, let’s look at how we can validate the token in PHP. As always, we’d include Composer’s autoloader. We could then, optionally, check if the correct request method’s been used. I’ve skipped over the code to do that, to continue focusing on the JWT-specific code:
iss !== $serverName ||
$token->nbf > $now->getTimestamp() ||
$token->exp < $now->getTimestamp())
header(‘HTTP/1.1 401 Unauthorized’);

If the token isn’t valid because, for example, the token has expired, the user will be sent an HTTP 401 Unauthorized header, and the script will exit.
If the process to decode the JWT fails, it could be that:
The number of segments provided did not match the standard three as described earlier.
The header or the payload is not a valid JSON string
The signature is invalid, which means the data was tampered with!
The nbf claim is set in the JWT with a timestamp when the current timestamp is less than that.
The iat claim is set in the JWT with a timestamp when the current timestamp is less than that.
The exp claim is set in the JWT with a timestamp when the current timestamp is more than that.
As you can see, JWT has a nice set of controls that will mark it as invalid, without the need to manually revoke it or check it against a list of valid tokens.
If the decode and validation process succeeds, the user will be allowed to make the request, and will be sent the appropriate response.
In Conclusion
That’s a quick introduction to JSON Web Tokens, or JWTs, and how to use them in PHP-based applications. From here on, you can try to implement JWTs in your next API, maybe trying some other signing algorithms that use asymmetric keys like RS256, or integrating it in an existing OAUTH2 authentication server to be the API key.
If you have any comments or questions, feel free to get in touch on Twitter.

Coded at

Share your love

Leave a Reply