DEV Community

Nacho Colomina Torregrosa
Nacho Colomina Torregrosa

Posted 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.

Top comments (0)