BookStackApp/BookStack · error · OidcInvalidTokenException
Missing token issued at time value
Error message
Missing token issued at time value
What it means
OidcIdToken::validateTokenClaims performs OIDC ID token claim validation step 6: the 'iat' (issued-at) claim must be present to reject tokens issued too far from current time and limit nonce storage windows. When the decoded token payload has an empty or missing 'iat' claim, this exception is thrown. It indicates the identity provider issued a non-conformant ID token.
Source
Thrown at app/Access/Oidc/OidcIdToken.php:67
}
// 5. The current time MUST be before the time represented by the exp Claim
// (possibly allowing for some small leeway to account for clock skew).
if (empty($this->payload['exp'])) {
throw new OidcInvalidTokenException('Missing token expiration time value');
}
$skewSeconds = 120;
$now = time();
if ($now >= (intval($this->payload['exp']) + $skewSeconds)) {
throw new OidcInvalidTokenException('Token has expired');
}
// 6. The iat Claim can be used to reject tokens that were issued too far away from the current time,
// limiting the amount of time that nonces need to be stored to prevent attacks.
// The acceptable range is Client specific.
if (empty($this->payload['iat'])) {
throw new OidcInvalidTokenException('Missing token issued at time value');
}
$dayAgo = time() - 86400;
$iat = intval($this->payload['iat']);
if ($iat > ($now + $skewSeconds) || $iat < $dayAgo) {
throw new OidcInvalidTokenException('Token issue at time is not recent or is invalid');
}
// 7. If the acr Claim was requested, the Client SHOULD check that the asserted Claim Value is appropriate.
// The meaning and processing of acr Claim Values is out of scope for this document.
// NOTE: Not used for our case here. acr is not requested.
// 8. When a max_age request is made, the Client SHOULD check the auth_time Claim value and request
// re-authentication if it determines too much time has elapsed since the last End-User authentication.
// NOTE: Not used for our case here. A max_age request is not made.
// Custom: Ensure the "sub" (Subject) Claim exists and has a value.
if (empty($this->payload['sub'])) {View on GitHub (pinned to 18f8469a1c)
Solutions
- Fix the identity provider / token issuer so the ID token includes a valid NumericDate 'iat' claim
- Check that the JWT is not being decoded/filtered in a way that drops claims before validation
- If generating tokens in tests, add 'iat' => time() to the payload
- If you cannot fix the IdP, pre-decode the token and reject/warn before calling validate()
Example fix
// before (test token payload) ['iss' => $iss, 'aud' => $aud, 'sub' => $sub, 'exp' => time()+3600] // after ['iss' => $iss, 'aud' => $aud, 'sub' => $sub, 'exp' => time()+3600, 'iat' => time()]
Defensive patterns
Strategy: validation
Validate before calling
$payload = json_decode(base64_decode(str_replace('-', '+', str_replace('_', '/', explode('.', $idToken)[1]))), true);
if (empty($payload['iat'])) { throw new \RuntimeException('ID token missing iat claim'); } Try / catch
try { $token->validate($now); } catch (OidcInvalidTokenException $e) { if ($e->getMessage() === 'Missing token issued at time value') { /* reject token / alert on IdP conformance */ } throw $e; } Prevention
- Pre-decode and sanity-check required claims (iss, aud, exp, iat, sub) before calling validate()
- Add IdP conformance tests that assert iat is present
- Log the full payload (excluding PII) when validation fails to diagnose issuer issues
When it happens
Trigger: Calling validate() on an OidcIdToken whose decoded JWT payload lacks the 'iat' claim or has it set to 0/empty (e.g. empty($this->payload['iat']) evaluates true).
Common situations: Misconfigured or minimal IdP implementations that omit 'iat'; hand-crafted or test tokens missing claims; tokens mangled by proxies that strip claims; using a token endpoint response whose id_token was built by custom middleware.
Related errors
- Token audience value has ' . count($aud) . ' values, Expecte
- Token authorized party exists but does not match the expecte
- Missing token expiration time value
- Missing token subject value
- Missing token audience value
AI-assisted analysis of BookStackApp/BookStack@18f8469a1c (2026-09-02).
Data as JSON: /api/errors/7de3e527ead8c03a.
Report an issue: GitHub.