{"record":{"id":"54dc1bde1ae06885","repo":"hcengineering/platform","slug":"err-message","errorCode":null,"errorMessage":"err.message","messagePattern":"err\\.message","errorType":"exception","errorClass":"TokenError","httpStatus":null,"severity":"error","filePath":"foundations/core/packages/token/src/token.ts","lineNumber":121,"sourceCode":"      account: accountUuid,\n      workspace: workspaceUuid,\n      grant: sanitizedGrant,\n      sub,\n      exp,\n      nbf\n    },\n    secret ?? getSecret()\n  )\n}\n\n/**\n * @public\n */\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  }","sourceCodeStart":103,"sourceCodeEnd":139,"githubUrl":"https://github.com/hcengineering/platform/blob/63e28dc96483967b2fc21c881b3f1023c1de7718/foundations/core/packages/token/src/token.ts#L103-L139","documentation":"decodeToken wraps the underlying JWT decode/verify call; any failure (bad signature, malformed token, wrong secret) is rethrown as a TokenError carrying the underlying err.message. It is the library's single funnel for token decoding failures.","triggerScenarios":"Calling decodeToken with a token that is truncated, tampered, signed with a different secret, or not a JWT at all; or with verify=true and a mismatched secret (getSecret() result differing from the signing secret).","commonSituations":"Secrets differing across services/environments (JWT_SECRET env mismatch), tokens from another deployment, expired/corrupted cookies or Authorization headers, copies missing trailing characters.","solutions":["Ensure the same secret is configured on issuer and verifier (check the secret env var / metadata)","Inspect the wrapped err.message — it names the underlying cause (e.g. signature mismatch, malformed JWT)","Confirm the token is passed in full, without truncation or added whitespace/quotes","Re-issue a fresh token if the token itself is corrupt or stale"],"exampleFix":"// before\nconst t = decodeToken(authHeader) // 'Bearer eyJ...' including prefix -> malformed\n// after\nconst raw = authHeader.replace(/^Bearer\\s+/i, '')\nconst t = decodeToken(raw)","handlingStrategy":"try-catch","validationCode":"if (typeof token !== 'string' || token.split('.').length !== 3) {\n  throw new Error('token is not a well-formed JWT (expected 3 dot-separated parts)')\n}","typeGuard":"function looksLikeJwt(v: unknown): v is string {\n  return typeof v === 'string' && /^[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]*$/.test(v)\n}","tryCatchPattern":"try {\n  const decoded = decodeToken(token, true)\n} catch (e) {\n  if (e instanceof TokenError) {\n    // e.message carries the underlying cause: signature, malformed, etc.\n    throw new UnauthorizedError(`bad token: ${e.message}`)\n  }\n  throw e\n}","preventionTips":["Strip 'Bearer ' prefixes and surrounding quotes before decoding","Keep JWT secrets identical across all services and environments (shared config)","Log token prefixes (never full tokens) to diagnose truncation","Use decodeTokenVerbose to get the decoded payload in warnings when verification fails"],"tags":["jwt","token","decoding"],"backgroundTag":"jwt-decode-failed","analyzedSha":"63e28dc96483967b2fc21c881b3f1023c1de7718","analyzedAt":"2026-08-29T15:21:27.377Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}