This tutorial has a new version, check it out!

LexikJWTAuthenticationBundle

Keep on Learning!

If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.

Start your All-Access Pass
Buy just this tutorial for $10.00

Google for LexikJWTAuthenticationBundle. This bundle is going to make creating and validating JSON web tokens as much fun as eating ice cream. Click to read the documentation. And now, you guys know the drill. Copy the library name from the composer require line and run:

composer require lexik/jwt-authentication-bundle

Tip

The latest version of lexik/jwt-authentication-bundle requires Symfony 3.4 or higher. Run composer require 'lexik/jwt-authentication-bundle:v2.4' to install this bundle for older versions of Symfony, like the one that is used in this screencast. Or, upgrade your project's dependencies.

While we're waiting for Jordi, I mean Composer to download that for us, let's keep busy. Copy the new bundle line and put that into AppKernel:

... lines 1 - 5
class AppKernel extends Kernel
{
public function registerBundles()
{
$bundles = array(
... lines 11 - 20
new Lexik\Bundle\JWTAuthenticationBundle\LexikJWTAuthenticationBundle(),
);
... lines 23 - 32
}
... lines 34 - 51
}

Great!

Generating the Public and Private Key

Our first goal is to write some code that can take an array of information - like a user's username - and turn that into a JSON web token. This bundle gives us a really handy service to do that.

But before we can use it, we need to generate a public and private key. The private, or secret key, will be used to sign the JSON web tokens. And no matter what the FBI says, this must stay private: if someone else gets it, they'll be able to create new JSON web tokens with whatever information they want - like with someone else's username to gain access to their account.

Copy the first line, head to the terminal and wait for Composer to finish all its thinking. Come on Jordi! Don't worry about the error: this bundle has some required configuration that we're about to provide.

First, make a new directory to hold the keys:

mkdir var/jwt

Next, copy the second line to create a private key, but change its path to the var/jwt directory:

openssl genrsa -out var/jwt/private.pem -aes256 4096

This asks you for a password - give it one! It adds another layer of security in case somebody gets your private key. I'll use happyapi. Perfect!

Last step: copy the final line and remove app at the beginning and the end to point to the var/jwt directory:

openssl rsa -pubout -in var/jwt/private.pem -out var/jwt/public.pem

Type in the password you just set. This creates a public key. It'll be used to verify that a JWT hasn't been tampered with. It's not private, but you probably won't need to share it, unless someone else - or some other app - needs to also verify that a JWT we created is valid.

We now have a private.pem and a public.pem. You probably will not want to commit these to your repository: the private key needs to stay secret. But there's good news! You can create a key pair to use locally and then generate a totally different key pair on production when you deploy. They don't need to be the same. Just don't change the keys on production: that will invalidate any existing JSON web tokens that your clients have.

Configuring the Bundle

Ok, last step: tell the bundle about our keys. Copy the configuration from the docs and open up app/config/config.yml. Paste this at the bottom:

... lines 1 - 72
lexik_jwt_authentication:
private_key_path: %kernel.root_dir%/../var/jwt/private.pem
public_key_path: %kernel.root_dir%/../var/jwt/public.pem
pass_phrase: %jwt_key_pass_phrase%
token_ttl: 3600

Instead of using all these fancy parameters, it's fine to set the path directly: private_key_path: %kernel.root_dir% - that's the app/ directory - /../var/jwt/private.pem. Do the same for the public key, with public.pem. Set the token_ttl to whatever you want: I'll use 3600: this means every token will be valid for only 1 hour.

Finally, open parameters.yml and add the jwt_key_pass_phrase, which for me is happyapi. Don't forget to add an empty setting also in parameters.yml.dist for future developers:

... line 1
parameters:
... lines 3 - 20
jwt_key_pass_phrase: ~

Phew! That's it! We had to generate a public and private key, but now, life is going to be sweet. Run:

bin/console debug:container jwt

Select lexik_jwt_authentication.jwt_encoder. This is our new best friend for generating JSON web tokens.

Leave a comment!

This tutorial uses an older version of Symfony. The concepts of API tokens & JWT are still valid, but integration in newer Symfony versions may be different.

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "php": ">=5.5.9",
        "symfony/symfony": "3.0.*", // v3.0.3
        "doctrine/orm": "^2.5", // v2.5.4
        "doctrine/doctrine-bundle": "^1.6", // 1.6.2
        "doctrine/doctrine-cache-bundle": "^1.2", // 1.3.0
        "symfony/swiftmailer-bundle": "^2.3", // v2.3.11
        "symfony/monolog-bundle": "^2.8", // v2.10.0
        "sensio/distribution-bundle": "^5.0", // v5.0.4
        "sensio/framework-extra-bundle": "^3.0.2", // v3.0.14
        "incenteev/composer-parameter-handler": "~2.0", // v2.1.2
        "jms/serializer-bundle": "^1.1.0", // 1.1.0
        "white-october/pagerfanta-bundle": "^1.0", // v1.0.5
        "lexik/jwt-authentication-bundle": "^1.4" // v1.4.3
    },
    "require-dev": {
        "sensio/generator-bundle": "^3.0", // v3.0.6
        "symfony/phpunit-bridge": "^3.0", // v3.0.3
        "behat/behat": "~3.1@dev", // dev-master
        "behat/mink-extension": "~2.2.0", // v2.2
        "behat/mink-goutte-driver": "~1.2.0", // v1.2.1
        "behat/mink-selenium2-driver": "~1.3.0", // v1.3.1
        "phpunit/phpunit": "~4.6.0", // 4.6.10
        "doctrine/doctrine-fixtures-bundle": "^2.3" // 2.3.0
    }
}