{"record":{"id":"87ac6f0c9f8fba60","repo":"hcengineering/platform","slug":"failed-to-verify-token","errorCode":null,"errorMessage":"Failed to verify token","messagePattern":"Failed to verify token","errorType":"exception","errorClass":"TokenError","httpStatus":null,"severity":"warning","filePath":"foundations/core/packages/token/src/token.ts","lineNumber":134,"sourceCode":" */\nexport function decodeToken (token: string, verify: boolean = true, secret?: string): Token {\n  try {\n    return decode(token, secret ?? getSecret(), !verify)\n  } catch (err: any) {\n    throw new TokenError(err.message)\n  }\n}\n\n/**\n * @public\n */\nexport function decodeTokenVerbose (ctx: MeasureContext, token: string): Token {\n  try {\n    return decodeToken(token)\n  } catch (err: any) {\n    try {\n      const decode = decodeToken(token, false)\n      ctx.warn('Failed to verify token', { ...decode })\n    } catch (err2: any) {\n      // Nothing to do\n    }\n    throw new TokenError(err.message)\n  }\n}\n\n/**\n * Checks whether a token has passed its `exp` (seconds since epoch) deadline.\n * `decodeToken` only verifies the signature — expiry must be checked separately.\n * @public\n */\nexport function isTokenExpired (token: Token, now: number = Date.now()): boolean {\n  return token.exp !== undefined && token.exp * 1000 <= now\n}\n\n/**\n * Resolves whether a revokable API token (identified by `extra.apiTokenId`)","sourceCodeStart":116,"sourceCodeEnd":152,"githubUrl":"https://github.com/hcengineering/platform/blob/63e28dc96483967b2fc21c881b3f1023c1de7718/foundations/core/packages/token/src/token.ts#L116-L152","documentation":"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.","triggerScenarios":"Calling decodeTokenVerbose with a token whose signature check fails, which is expired, or which is malformed and cannot even be decoded without verification.","commonSituations":"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.","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"],"exampleFix":"// before\nconst token = staleTokenFromStorage\nconst data = decodeTokenVerbose(ctx, token) // throws TokenError\n// after\nlet data\ntry {\n  data = decodeTokenVerbose(ctx, staleTokenFromStorage)\n} catch {\n  data = decodeTokenVerbose(ctx, await requestNewToken())\n}","handlingStrategy":"try-catch","validationCode":"function isTokenUsable(token: string): boolean {\n  return typeof token === 'string' && token.split('.').length === 3 && token.length > 20\n}","typeGuard":"function isTokenError(e: unknown): e is TokenError {\n  return e instanceof TokenError\n}","tryCatchPattern":"try {\n  data = decodeTokenVerbose(ctx, token)\n} catch (err) {\n  if (isTokenError(err)) {\n    ctx.warn('token unusable, re-authenticating')\n    token = await fetchNewToken()\n    data = decodeTokenVerbose(ctx, token)\n  } else throw err\n}","preventionTips":["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"],"tags":["typescript","jwt","authentication","token"],"backgroundTag":"jwt-token-verification-failed","analyzedSha":"63e28dc96483967b2fc21c881b3f1023c1de7718","analyzedAt":"2026-08-29T15:21:27.377Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}