DEV Community

Nacho Colomina Torregrosa
Nacho Colomina Torregrosa

Posted on • Updated on

Using a Symfony secret to encode your JWT Tokens

Introduction

In this post, I am going to show you how to generate a secret by using symfony vaults and then how to use that secret to encode and decode a JWT Token using the firebase-jwt php component.

Generating the secret

To generate a secret we must first generate the encryption keys. This can be done using the following command:

 bin/console secrets:generate-keys
Enter fullscreen mode Exit fullscreen mode

This will generate a key pair in the following files:

  • config/secrets/{env}/{env}.encrypt.public.php
  • config/secrets/{env}/{env}.decrypt.private.php

The {env} value will depend on the enviroment you are working. If you are developing in local it should be "dev".

Now we have generated the key-pair, we can create a secret. To do it, let's execute the following command:

bin/console secrets:set JWT_SECRET
Enter fullscreen mode Exit fullscreen mode

The command will ask you for the secret value. Write it and press enter to save it.

Binding the JWT_SECRET to a variable

As we can get the JWT_SECRET value as we'd do with any other environment variable, let's bind a variable to it in our services.yaml file

services:
    _defaults:
        autowire: true
        autoconfigure: true 
        bind:
            # Other vars
            $jwtSecret: '%env(JWT_SECRET)%'
Enter fullscreen mode Exit fullscreen mode

Install the Firebase JWT PHP component

Let's use composer to install the component:

composer require firebase/php-jwt
Enter fullscreen mode Exit fullscreen mode

If you do not have sodium installed, install it using composer too.

composer require paragonie/sodium_compat
Enter fullscreen mode Exit fullscreen mode

Use the secret to encode and decode a jwt token

Let's create a service to encapsulate the logic which will encode and decode the tokens.

namespace App\Service\Token

use Firebase\JWT\JWT;
use Firebase\JWT\Key;

class TokenEncoder
{
    public function __construct(
        private readonly string $jwtSecret,
    ){}

    public function encode(string $exp, string $identifier): string
    {
        return JWT::encode([
            'exp'  => (new \DateTime())->add(\DateInterval::createFromDateString($exp))->getTimestamp(),
            'nbf'  => (new \DateTime())->getTimestamp(),
            'id' => $identifier
        ], $this->jwtSecret, 'HS256');
    }

    public function decode(string $token): string
    {
        $credentials = (array)JWT::decode($token, new Key($this->jwtSecret, 'HS256'));
    }
}

Enter fullscreen mode Exit fullscreen mode

Let's analyze the service step by step:

  • The constructor injects the recently binded variable in the services.yaml file ("$jwtSecret") which holds the JWT_SECRET value.
  • The encode method encodes the token. It receives:
    • The array to encode with the token. It contains the following keys:
      • exp: The token expiration time as a timestamp
      • nbf: Indicates when the token starts to be valid. We set the current timestamp, that is, when the token is created it starts to be valid until the expiration date.
      • id: An identifier (Could be a user or application identifier).
    • The secret to encode the token with (we use our $jwtSecret binded var).
    • The encryption algorithm. We choose the HS256.

You can learn more about HS256 and RS256 here. We choose HS256 since it is a symmetric hashing and we only need one secret key.

Conclusion

In this post we have learned how we can securely store a secret within symfony secrets and how to use it to generate a JWT token. This could be useful on API's which use JWT tokens to autenticate their users or applications.
If you enjoy my content and like the Symfony framework, consider reading my book: Building an Operation-Oriented Api using PHP and the Symfony Framework: A step-by-step guide

Top comments (0)