Laravel JWT provides a seamless JWT (JSON Web Tokens) implementation that integrates directly with Laravels authentication library allowing for stateless API authentication.
To install this package simply run the following command.
composer require sprocketbox/laravel-jwt
This package uses auto-discovery to register the service provider but if you'd rather do it manually, the service provider is:
Sprocketbox\JWT\JWTServiceProvider
There are no extra configuration files required, but there are a few extra options when configuring a guard in
config/auth.php
.
Here's an example configuration for a JWT guard.
'api' => [
'driver' => 'jwt',
'provider' => 'users',
'key' => env('JWT_KEY_API'),
'signer' => Lcobucci\JWT\Signer\Hmac\Sha256::class,
'ttl' => 'P1M',
],
If you don't care to dive into all the extra bits you can create a very minimal JWT guard config by:
jwt
'key' => env('JWT_KEY_GUARD'),
where GUARD
is the name of your auth guardphp artisan jwt:generate guard
where guard
is the name of your auth guard.env.example
fileIf you wish to use the JWT driver, just set the driver
option to jwt
.
If you wish for your tokens to be signed you must, at the very least, provide a key using the key
option.
As the default signature uses a SHA256 HMAC, I recommend a 64 character key.
It's best you place this key in your env file as JWT_KEY
or something similar.
By default this package will create a signature using a SHA256 HMAC, but if you wish to change that you can
set the signer
option to be the class name of a valid signer.
The default is Lcobucci\JWT\Signer\Hmac\Sha256
but there are other options in the
Lcobucci\JWT\Signer
namespace. If you wish to keep the
default you can omit this option.
By default this package will set the TTL (total time to live) to 1 month, or more precisely P1M
. If you wish to change
this you can set the ttl
config value to be a valid interval spec.
If you wish to generate the token yourself you can provide a custom generator like so:
Auth::guard('api')->setTokenGenerator(function (\Illuminate\Contracts\Auth\Authenticatable $user, \Sprocketbox\JWT\JWTGuard $guard) {
return $instanceOfBuilder;
});
The generator must return an instance of Lcobucci\JWT\Builder
.
If you wish to provide custom validation for your token you may provide it like so:
Auth::guard('api')->setTokenValidator(function (\Lcobucci\JWT\Token $token, \Sprocketbox\JWT\JWTGuard $guard) {
return $validationState;
});
If the validation fails you must return false
. Any other return type, including null
will be treated as a pass.
In some situations you may find that the static signing method and key in the config isn't sufficient. If that is the case, you can provide an override like so:
Auth::guard('api')->setTokenSigner(function (\Sprocketbox\JWT\JWTGuard $guard): array {
return [
new config('auth.guards.api.signer'),
new \Lcobucci\JWT\Signer\Key(config('auth.guards.api.key'))
];
});
This must return an array with two indexes, the first being the signer and the second being the key.
You can generate a key per guard by running the jwt:generate
command with the name of the guard. The
commands signature is:
jwt:generate {guard}
{--length : The length of the key, defaults to 32}
{--show : Display the key instead of modifying files}
{--force : Force the operation to run when in production}
This package functions in an almost identical way to Laravels session authentication, with a few exceptions.
The token is loaded as a bearer token, so you must provide it as a bearer token in the HTTP authorization header.
Authorization: Bearer TOKEN_HERE
If you passed true
as the second argument for attempt()
the token will be automatically provided
by the cookie, removing the need to manually pass the token.
The Auth::attempt($credentials)
method is missing the second parameter (remember me) and instead of returning a
boolean, returns an instance of Lcobucci\JWT\Token
. Casting this object to a string will give you the
actual JWT token.
If you wish to get the token currently being used, as in, the currently authenticated token, you can call the token()
method on the guard, the same way you would call user()
Take the following code as an example:
$input = $request->only('email', 'password');
$token = Auth::guard('api')->attempt($input);
if ($token !== null) {
return response()->json(['token' => (string) $token]);
}
return response()->json(null, 401);
If you pass true
as the second argument for attempt()
the guard will create a HTTP only
(Not accessible via javascript) cookie. This will prevent you from having to store the token in
the browsers localStorage.
To make sure that the cookie is added to the response you need to add the following middleware to your routes.
Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class
It makes sense to add this to the api
group. Though it's not technically required, I recommend that
you also add the following middleware to encrypt the cookies.
App\Http\Middleware\EncryptCookies::class
It's also advised to simply return a 204
response when using this method so that the token data isn't
output anywhere.
The login and authenticated events are called just like with the session guard.
By default the token generation is somewhat opinionated, but that is because this is the initial version of this package.
The following covers how the claims are populated.
iss
) is set to config('app.url')
aud
) is also set to config('app.url')
jti
) is a UUID4 generated with the tokeniat
) is set to the current timestampexp
) is set to the current timestamp + the value of ttl
(defaults to P1M
)sub
) is set to the value of Authenticatable::getAuthIdentifier()
The token is generated using the lcobucci/jwt package.
There are a couple of things that I wish to add into later versions of this package. I've made an attempt to list them all here, as a sort of roadmap.
jti
, aud
and exp
to blacklist and revoke tokens