Skip to main content
Version: 5.x

JWT Authentication with Policier

Introduction​

Policier lets you validate requests using JWT (JSON Web Tokens).

Installation​

To install the package, you must use composer (PHP's package manager) like this:

composer require bowphp/policier

Configuration​

You can review all the configuration options here.

config/policier.php
return [
/**
* Token expiration time
*/
"exp" => 3600,

/**
* The token is usable after this time
*/
"nbf" => 60,

/**
* The token was issued at
*/
"iat" => 60,

/**
* Configure the issuer
*/
"iss" => "localhost",

/**
* Configure the audience
*/
"aud" => "localhost",

/**
* Hashing algorithm used
*
* HS256, HS384, HS512, RS256, RS384, RS512, ES256, ES384, ES512,
*/
"alg" => "HS512",

/**
* Your signature; this field is required for all hashing types except RSA
*/
'signkey' => null,

/**
* Signature using your RSA, which is loaded automatically if the hashing key is of RSA type
*/
"keychain" => [
/**
* Path to your private key
*/
"private" => null,

/**
* Path to your public key
*/
"public" => null
]
];

Usage​

Policier is very simple to use and has a clear API. The configuration returns a singleton.

use Policier\Policier;

$configure = require "/path/to/config/file.php";

$policier = Policier::configure($configure);

You can also do it like this:

use Policier\Policier;

$configure = require "/path/to/config/file.php";

Policier::configure($configure);

$policier = Policier::getInstance();

After configuration, you can use the policier helper:

policier($action, ...$args);
Available actions

The action value must be one of these values: encode, decode, parse, verify, validate.

Updating or Retrieving the Configuration​

Updating the Configuration​

You can update the base configuration with the setConfig method. It takes an array of keys to merge with the existing configuration:

$policier->setConfig([
'exp' => time() + 72000,
'iss' => 'api.example.com',
]);

Retrieving the Configuration​

You can also get configuration information with the getConfig method:

$policier->getConfig('exp');

Encoding a Token​

Encode a token quickly:

$id = uniqid();

$claims = [
"name" => "Franck",
"nickname" => "papac",
"logged" => true
];

$token = $policier->encode($id, $claims);

$token->expireIn(); // Expired In
$token->getToken(); // Token value

echo $token;
//=> eyJ0eX...OiJKV1.eyJpc3Mi...OiJsb2.l7v0bS0r...qnK1IeR
Token Instance

$token is an instance of Policier\Token and implements the magic __toString method. You can get the expiration time with expireIn and getToken to retrieve the token value.

Via the helper:

policier('encode', $id, $claims);

Decoding a Token​

decode() returns an instance of Policier\Token. Use its getHeaders() / getHeader($name) / getClaim($name) / getClaims() methods to extract information from it:

$result = $policier->decode($token);

$result->getHeaders(); // array
echo $result->getClaim('name'); // => Franck

Via the helper:

policier('decode', $token);

Parsing a Token​

$token = $policier->parse($token);

$token->hasHeader("old") // Check if the header exists
$token->getHeader("alg", $default = null); // Get a header
$token->getHeaders(); // Get all headers

$token->hasClaim("name") // Check if the claim exists
$token->getClaim("name", $default = null); // Get a claim
$token->getClaims(); // Get all claims

$token->isExpired(); // Check if the token has expired

echo $token->getClaim("name");
//=> Franck

Via the helper:

policier('parse', $token);

Verifying a Token​

Check whether the token is valid with all JWT attributes.

$verified = $policier->verify($token);

if ($verified) {
echo "Token est valide";
} else {
echo "Token n'est pas valide";
}

Via the helper:

policier('verify', $token);

Validating a Token​

Check both the token's signature and that it actually belongs to a given subject (the same $id you passed to encode()). The validate method takes this identifier as its second argument β€” not an array of claims.

$id = $token->getClaim('jti'); // or any other identifier you used

$validated = $policier->validate((string) $token, $id);

if ($validated) {
echo "Token valide pour le sujet {$id}";
} else {
echo "Token invalide ou expirΓ©";
}

Via the helper:

policier('validate', $token, $id);
Verifying arbitrary claims

If you also want to check application-side claims (name, role, etc.), do the comparison yourself after decode():

$decoded = $policier->decode($token);
if ($decoded->getClaim('nickname') !== 'papac') {
// unexpected claim
}

BowPHP and Policier​

If you use BowPHP, you can use the configuration plugin Policier\Bow\PolicierConfiguration::class and the middleware Policier\Bow\PolicierMiddleware::class.

Wire up the configuration in app\Kernel.php:

app\Kernel.php
public function middlewares()
{
return [
...
'policier' => \Policier\Bow\PolicierMiddleware::class,
...
];
}

public function configurations()
{
return [
...
\Policier\Bow\PolicierConfiguration::class,
...
];
}

Use the middleware:

$app->get('/api', function () {
$token = policier()->getToken();
})->middleware('policier');

The token has been parsed into the Policier instance during the middleware process via the plug method. After the middleware runs, you can:

  • Get the token with getToken
  • Decode the token with getDecodeToken
  • Parse the token with getParsedToken

Customizing the Middleware​

Advanced customization

You can create another middleware that extends the default middleware Policier\Bow\PolicierMiddleware::class. This gives you the ability to change the error messages by overriding the getUnauthorizedMessage, getExpirationMessage, getExpirationStatusCode, and getUnauthorizedStatusCode methods.

php bow add:middleware CustomPolicierMiddleware

And then, you can do this:

use Bow\Http\Request;
use Policier\Bow\PolicierMiddleware;

class CustomPolicierMiddleware extends PolicierMiddleware
{
/**
* Get the error message
*
* @return array
*/
public function getUnauthorizedMessage()
{
return [
'message' => 'unauthorized',
'error' => true
];
}

/**
* Get the token expiration message
*
* @return array
*/
public function getExpirationMessage()
{
return [
'message' => 'token is expired',
'expired' => true,
'error' => true
];
}

/**
* Get the unauthorized response code
*
* @return int
*/
public function getUnauthorizedStatusCode()
{
return 403;
}

/**
* Get the response code for expiration
*
* @return int
*/
public function getExpirationStatusCode()
{
return 403;
}
}

Publishing the middleware​

Publishing the custom middleware

To publish the custom middleware and override Policier's default one, simply add the middleware in the app/Kernel.php file with the policier key.

public function middlewares()
{
return [
...
'policier' => \App\Middleware\CustomPolicierMiddleware::class,
...
];
}

Is something missing?

If you run into problems with the documentation or have suggestions to improve the documentation or the project in general, please open an issue for us, or send a tweet mentioning the Twitter account @bowframework or directly on github.