How to setup JWT authentication with Symfony
LexikJWTAuthenticationBundle is Symfony’s officially supported JSON Web Token authentication bundle.

It turns your basic form login into a JSON Web Token (JWT) authentication mechanism, without you having to change anything in your code.
This can be pretty handy if you want to transform your Symfony project into an API that will be used by a separate front-end.
LexikJWTAuthenticationBundle adds JWT authentication to your project, but it doesn’t replace any other authentication mechanisms, meaning you can still use a form login after the setup of JWT authentication.
This bundle requires Symfony 4.4 and the openssl PHP extension.
Before anything, make sure you have a User provider configured in your Symfony project.
Setup
To get started, install the dependency by running the following composer command:
composer require "lexik/jwt-authentication-bundle"Now that the bundle is installed (Symfony Flex added it to your config/bundles.php file automatically), we need to generate a set of keypairs that will be used to encode the to-be generated JSON Web Tokens.
This is done by running a Symfony command provided by the bundle:
bin/console lexik:jwt:generate-keypairThe keypair is generated by default in the config/jwt folder.
Configuration
Let’s configure the SSL keys and JWT passphrase in our .env file
JWT_SECRET_KEY=%kernel.project_dir%/config/jwt/private.pem
JWT_PUBLIC_KEY=%kernel.project_dir%/config/jwt/public.pem
JWT_PASSPHRASE=<your passphrase here, it can be anything>A config/packages/lexik_jwt_authentication.yaml file should have been generated by Symfony and contains the following configuration by default:
lexik_jwt_authentication:
secret_key: '%env(resolve:JWT_SECRET_KEY)%'
public_key: '%env(resolve:JWT_PUBLIC_KEY)%'
pass_phrase: '%env(JWT_PASSPHRASE)%'
token_ttl: 3600Once this is done, navigate to your config/packages/security.yaml file and modify your firewalls to add the following:
login:
pattern: ^/api/login
stateless: true
json_login:
check_path: /api/login_check
success_handler: lexik_jwt_authentication.handler.authentication_success
failure_handler: lexik_jwt_authentication.handler.authentication_failure
api:
pattern: ^/api
stateless: true
jwt: ~and add this entry to your access-control rules as the first one:
- { path: ^/api/login, roles: PUBLIC_ACCESS }This makes sure that your JWT login route is available to anyone without authentication.
Lastly, add this to your config/routes.yaml file:
api_login_check:
path: /api/login_checkEverything is now configured, authenticating with JWT is now possible.
To use this authentication mechanism, request a token that you will include in your future requests.
To get an authentication token, simply send a POST request to the configured endpoint (in our case, /api/login_check), with a body formatted like the following:
{
"username": "your username",
"password": "your password"
}The response will contain the following:
{
"token": "your token"
}To authenticate your requests, simply include this token as a normal bearer token: include a header:
Authorization: Bearer <your token here>
That’s it! Every request containing a valid token will now handle authentication with the user provider you configured, meaning that $this->getUser() works the same way it does as with a basic form authentication.
When authenticating with an expired token, the server will send a 401 HTTP Unauthorized response.
Refresh tokens are not basically handled by LexikJWTAuthenticationBundle, but can be added using JWTRefreshTokenBundle.
If this article helped you or gathered your interest, you may be interested in my other articles! I mainly publish stuff about PHP and the Symfony ecosystem. Follow my account to read my future content!