{"record":{"id":"71f14a7e67dc62b2","repo":"hcengineering/platform","slug":"token-error-71f14a","errorCode":null,"errorMessage":"Token error","messagePattern":"Token error","errorType":"http","errorClass":null,"httpStatus":401,"severity":"error","filePath":"services/payment/pod-payment/src/middleware.ts","lineNumber":30,"sourceCode":"// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n\nimport type { NextFunction, Request, Response } from 'express'\nimport { extractToken, getAccountClient } from '@hcengineering/server-client'\nimport { AccountRole, systemAccountUuid } from '@hcengineering/core'\nimport { Token } from '@hcengineering/server-token'\nimport type { LoginInfo, LoginInfoRequest, WorkspaceLoginInfo } from '@hcengineering/account-client'\n\nexport interface RequestWithAuth extends Request {\n  token?: Token\n  loginInfo?: LoginInfo | WorkspaceLoginInfo | LoginInfoRequest\n}\n\nexport const withToken = (req: RequestWithAuth, res: Response, next: NextFunction): void => {\n  const token = extractToken(req.headers)\n  if (token === undefined || token == null) {\n    res.status(401).json({ message: 'Token error' }).end()\n    return\n  }\n  req.token = token\n  next()\n}\n\nexport const withAdmin = (req: RequestWithAuth, res: Response, next: NextFunction): void => {\n  if (req.token === undefined || req.token == null) {\n    res.status(401).json({ message: 'Token error' }).end()\n    return\n  }\n  if (req.token.account !== systemAccountUuid && req.token.extra?.admin !== 'true') {\n    res.status(401).json({ message: 'Admins only' }).end()\n    return\n  }\n  next()\n}\n","sourceCodeStart":12,"sourceCodeEnd":48,"githubUrl":"https://github.com/hcengineering/platform/blob/63e28dc96483967b2fc21c881b3f1023c1de7718/services/payment/pod-payment/src/middleware.ts#L12-L48","documentation":"The withToken Express middleware rejects a request with 401 'Token error' when no bearer token can be extracted from the request headers via extractToken. This middleware is a gateway guard: without a token the request never reaches the route handler. It exists so that downstream code can assume req.token is always set.","triggerScenarios":"Any request routed through withToken whose headers lack a token — typically a missing or malformed Authorization header (e.g. no 'Authorization: Bearer <token>' header at all, wrong header name, or a client that stripped the header).","commonSituations":"Forgetting to attach the Authorization header in a frontend fetch/axios call; a proxy or API gateway (e.g. nginx, Kong) dropping the Authorization header; calling the payment pod directly from curl/Postman without auth; OAuth/JWT header casing issues like 'authorization' vs 'Authorization' after custom middleware manipulation.","solutions":["Add a valid 'Authorization: Bearer <token>' header to the request","Verify the client library actually sends headers (e.g. set headers in axios defaults/fetch options) and no proxy strips them","Confirm the request goes through the correct gateway/base URL that expects this auth scheme","If token extraction should support other header names, update extractToken in middleware.ts"],"exampleFix":"// before\nawait fetch('https://api.example.com/payment/orders')\n// after\nawait fetch('https://api.example.com/payment/orders', {\n  headers: { Authorization: `Bearer ${accessToken}` }\n})","handlingStrategy":"validation","validationCode":"const authHeader = headers['authorization'] ?? ''\nif (!authHeader.startsWith('Bearer ') || authHeader.length <= 'Bearer '.length) {\n  throw new Error('Request would fail: no bearer token in Authorization header')\n}","typeGuard":"function hasToken(headers: IncomingHttpHeaders): boolean {\n  const h = headers['authorization']\n  return typeof h === 'string' && h.startsWith('Bearer ') && h.slice(7).length > 0\n}","tryCatchPattern":"try {\n  const res = await callApi()\n} catch (err) {\n  if (err.response?.status === 401 && err.response.data?.message === 'Token error') {\n    // re-authenticate and attach token before retrying\n  }\n}","preventionTips":["Always attach the Authorization header centrally via an HTTP client interceptor","Add an integration test asserting every guarded route rejects unauthenticated calls with 401","Check proxies/gateways do not strip Authorization headers","Log client-side auth state before requests to catch missing tokens early"],"tags":["auth","http-401","middleware","missing-token"],"backgroundTag":"missing-authorization-header","analyzedSha":"63e28dc96483967b2fc21c881b3f1023c1de7718","analyzedAt":"2026-08-29T15:21:27.377Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}