tymondesigns/jwt-auth · critical · Tymon\JWTAuth\Exceptions\JWTException
Secret is not set.
Error message
Secret is not set.
What it means
Thrown by getSigningKey() when a symmetric algorithm (HS256/HS384/HS512) is configured and the 'secret' config value is falsy. Since buildConfig() runs in the provider constructor, the JWT service cannot be instantiated at all - the first attempt to issue or verify a token throws, usually surfacing as a 500 on authenticated routes.
Source
Thrown at src/Providers/JWT/Lcobucci.php:238
/**
* {@inheritdoc}
*
* @return \Lcobucci\JWT\Signer\Key
*
* @throws \Tymon\JWTAuth\Exceptions\JWTException
*/
protected function getSigningKey()
{
if ($this->isAsymmetric()) {
if (! $privateKey = $this->getPrivateKey()) {
throw new JWTException('Private key is not set.');
}
return $this->getKey($privateKey, $this->getPassphrase() ?? '');
}
if (! $secret = $this->getSecret()) {
throw new JWTException('Secret is not set.');
}
return $this->getKey($secret);
}
/**
* {@inheritdoc}
*
* @return \Lcobucci\JWT\Signer\Key
*
* @throws \Tymon\JWTAuth\Exceptions\JWTException
*/
protected function getVerificationKey()
{
if ($this->isAsymmetric()) {
if (! $public = $this->getPublicKey()) {
throw new JWTException('Public key is not set.');
}View on GitHub (pinned to 6c70930a92)
Solutions
- Generate and persist a secret: php artisan jwt:secret (writes JWT_SECRET to .env automatically; use --force to overwrite)
- Confirm the entry exists in every environment: grep JWT_SECRET .env, and check the platform's env/secret store for production
- Run php artisan config:clear after adding the secret (a stale config cache keeps null even once .env is fixed), then re-run config:cache if you use it
- Use the same JWT_SECRET across all services that issue or verify these tokens
Example fix
# before # .env has no JWT_SECRET line -> JWTException: Secret is not set. # after php artisan jwt:secret # .env now contains: JWT_SECRET=... (and run: php artisan config:clear)
Defensive patterns
Strategy: validation
Validate before calling
// Fail fast at boot instead of at the first login attempt
public function boot(): void
{
if (in_array(config('jwt.algo'), ['HS256', 'HS384', 'HS512'], true)
&& empty(config('jwt.secret'))) {
throw new RuntimeException('JWT_SECRET is not set - run: php artisan jwt:secret');
}
} Type guard
function hasJwtSecret(): bool
{
return !empty(config('jwt.secret'));
} Try / catch
use Tymon\JWTAuth\Exceptions\JWTException;
try {
$token = auth('api')->login($user);
} catch (JWTException $e) {
// 'Secret is not set.' is an environment problem - alert ops, do not blame the client
Log::critical('JWT secret missing', ['env' => app()->environment()]);
abort(500, 'token service unavailable');
} Prevention
- Run php artisan jwt:secret as part of every fresh install/CI bootstrap script
- Add a health check (e.g. /up) that asserts config('jwt.secret') is non-null in production
- After changing .env, always run config:clear (or rebuild config:cache) - stale cache is the most common recurrence
- Inject JWT_SECRET via the platform secret store rather than committing .env files
When it happens
Trigger: JWT_SECRET env var missing or empty in the running environment while JWT_ALGO is HS* (the default). Triggered by resolving auth('api'), calling auth()->login($user) / JWTAuth::fromUser(), or hitting any route behind auth:api middleware for the first time.
Common situations: Fresh install where `php artisan jwt:secret` was never run; .env missing the entry locally or on a new server; a deployed environment (Docker, Kubernetes, Forge, Vapor) whose secret variables were not provisioned; php artisan config:cache run before JWT_SECRET was set, so the cached config permanently holds null.
Understand the failure class
Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.
Related errors
- Could not create token: {exception message}
- Token Signature could not be verified.
- The given algorithm could not be found
- Private key is not set.
- Public key is not set.
AI-assisted analysis of tymondesigns/jwt-auth@6c70930a92 (2026-08-21).
Data as JSON: /api/errors/04a9e4fd5af0a7f2.
Report an issue: GitHub.