lcobucci/jwt · error · ConstraintViolation

"Issued At" claim missing

Error message

"Issued At" claim missing

What it means

StrictValidAt mandates the 'iat' (Issued At) claim; assertIssueTime throws '"Issued At" claim missing' when the claim set has no iat. Strict mode deliberately rejects tokens without issuance timestamps to prevent accepting tokens of unknown provenance.

Solutions

  1. Fix the issuer to always call ->issuedAt(new DateTimeImmutable(...)) when building tokens
  2. Use a less strict validator if your token profile does not guarantee iat
  3. Pre-check $token->claims()->has('iat') and reject with an explicit 'token missing iat' error at the boundary
  4. Reissue legacy tokens that predate the iat requirement

Example fix

// before
$builder->expiresAt($now->modify('+1 hour'));
// after
$builder->issuedAt($now)->expiresAt($now->modify('+1 hour'));
Defensive patterns

Strategy: validation

Validate before calling

if (! $token->claims()->has('iat')) {
    throw new InvalidArgumentException('Token must carry iat claim for StrictValidAt');
}

Type guard

function hasIssuedAtClaim(UnencryptedToken $t): bool { return $t->claims()->has('iat'); }

Try / catch

try {
    $validator->assert($token, new StrictValidAt($clock));
} catch (ConstraintViolation $e) {
    if (str_contains($e->getMessage(), '"Issued At" claim missing')) { /* reject; fix issuer */ }
}

Prevention

When it happens

Trigger: Validator::assert($token, new StrictValidAt(...)) on a token created without ->issuedAt(...) — the RegisteredClaims::ISSUED_AT claim is absent.

Common situations: Old token builders that only set exp; tokens minted by external systems that omit iat; moving from LooseValidAt/lenient checks to StrictValidAt causing legacy tokens to fail; test fixtures handcrafted without iat.

Related errors


AI-assisted analysis of lcobucci/jwt@375813049c (2026-09-14). Data as JSON: /api/errors/b95bd4dbd115cbd8. Report an issue: GitHub.

Appendix: source

Thrown at src/Validation/Constraint/StrictValidAt.php:77

    }

    /** @throws ConstraintViolation */
    private function assertMinimumTime(UnencryptedToken $token, DateTimeInterface $now): void
    {
        if (! $token->claims()->has(Token\RegisteredClaims::NOT_BEFORE)) {
            throw ConstraintViolation::error('"Not Before" claim missing', $this);
        }

        if (! $token->isMinimumTimeBefore($now)) {
            throw ConstraintViolation::error('The token cannot be used yet', $this);
        }
    }

    /** @throws ConstraintViolation */
    private function assertIssueTime(UnencryptedToken $token, DateTimeInterface $now): void
    {
        if (! $token->claims()->has(Token\RegisteredClaims::ISSUED_AT)) {
            throw ConstraintViolation::error('"Issued At" claim missing', $this);
        }

        if (! $token->hasBeenIssuedBefore($now)) {
            throw ConstraintViolation::error('The token was issued in the future', $this);
        }
    }
}

View on GitHub (pinned to 375813049c)