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
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
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)%'
Install the Firebase JWT PHP component
Let's use composer to install the component:
composer require firebase/php-jwt
If you do not have sodium installed, install it using composer too.
composer require paragonie/sodium_compat
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'));
}
}
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.
- The array to encode with the token. It contains the following keys:
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)