hcengineering/platform · warning · TokenError
Failed to verify token
Error message
Failed to verify token
What it means
decodeTokenVerbose wraps decodeToken and, when verification fails, attempts an unverified decode purely to log the token payload as a warning, then rethrows a TokenError with the underlying message. The 'Failed to verify token' log is diagnostic — the actual failure is the token signature/expiry/format problem inside decodeToken.
Source
Thrown at foundations/core/packages/token/src/token.ts:134
*/
export function decodeToken (token: string, verify: boolean = true, secret?: string): Token {
try {
return decode(token, secret ?? getSecret(), !verify)
} catch (err: any) {
throw new TokenError(err.message)
}
}
/**
* @public
*/
export function decodeTokenVerbose (ctx: MeasureContext, token: string): Token {
try {
return decodeToken(token)
} catch (err: any) {
try {
const decode = decodeToken(token, false)
ctx.warn('Failed to verify token', { ...decode })
} catch (err2: any) {
// Nothing to do
}
throw new TokenError(err.message)
}
}
/**
* Checks whether a token has passed its `exp` (seconds since epoch) deadline.
* `decodeToken` only verifies the signature — expiry must be checked separately.
* @public
*/
export function isTokenExpired (token: Token, now: number = Date.now()): boolean {
return token.exp !== undefined && token.exp * 1000 <= now
}
/**
* Resolves whether a revokable API token (identified by `extra.apiTokenId`)View on GitHub (pinned to 63e28dc964)
Solutions
- Have the client obtain a fresh token (re-authenticate)
- Ensure the token signing secret/keys match between issuer and verifier
- Check system clocks / token expiry configuration
- Inspect the logged decode payload in the warning to see which claim failed
Example fix
// before
const token = staleTokenFromStorage
const data = decodeTokenVerbose(ctx, token) // throws TokenError
// after
let data
try {
data = decodeTokenVerbose(ctx, staleTokenFromStorage)
} catch {
data = decodeTokenVerbose(ctx, await requestNewToken())
} Defensive patterns
Strategy: try-catch
Validate before calling
function isTokenUsable(token: string): boolean {
return typeof token === 'string' && token.split('.').length === 3 && token.length > 20
} Type guard
function isTokenError(e: unknown): e is TokenError {
return e instanceof TokenError
} Try / catch
try {
data = decodeTokenVerbose(ctx, token)
} catch (err) {
if (isTokenError(err)) {
ctx.warn('token unusable, re-authenticating')
token = await fetchNewToken()
data = decodeTokenVerbose(ctx, token)
} else throw err
} Prevention
- Refresh tokens before expiry (proactive renewal with jitter)
- Keep signing secrets in sync across services via config/secret manager
- Validate token shape before sending
- Monitor 'Failed to verify token' warnings for secret-mismatch spikes
When it happens
Trigger: Calling decodeTokenVerbose with a token whose signature check fails, which is expired, or which is malformed and cannot even be decoded without verification.
Common situations: Expired sessions after token TTL passes; tokens signed with a rotated/changed JWT secret; clients sending garbage or truncated token strings; clock skew between issuer and verifier.
Related errors
- Workspace or account not found in token
- nbf and exp are required when sub is not provided
- err.message
- Token expired
- Authentication token not specified
AI-assisted analysis of hcengineering/platform@63e28dc964 (2026-08-29).
Data as JSON: /api/errors/87ac6f0c9f8fba60.
Report an issue: GitHub.