{"record":{"id":"4a0ec19f32b00211","repo":"hcengineering/platform","slug":"unauthorized","errorCode":null,"errorMessage":"Unauthorized","messagePattern":"Unauthorized","errorType":"http","errorClass":"HttpError","httpStatus":401,"severity":"error","filePath":"pods/link-preview/src/middleware.ts","lineNumber":45,"sourceCode":"\nexport interface RequestWithAuth extends Request {\n  token?: Token\n}\n\nexport const keepAlive = (options: KeepAliveOptions): RequestHandler => {\n  const { timeout, max } = options\n  return (req: Request, res: Response, next: NextFunction) => {\n    res.setHeader('Connection', 'keep-alive')\n    res.setHeader('Keep-Alive', `timeout=${timeout}, max=${max}`)\n    next()\n  }\n}\n\nexport const withAuthorization = (req: RequestWithAuth, res: Response, next: NextFunction): void => {\n  try {\n    const token = extractToken(req.headers)\n    if (token == null) {\n      throw new HttpError(401, 'Unauthorized')\n    }\n    req.token = token\n\n    next()\n  } catch (err: any) {\n    next(err)\n  }\n}\n\nexport interface ErrorHandlerOptions {\n  ctx: MeasureContext\n}\n\nexport const errorHandler = (options: ErrorHandlerOptions): ErrorRequestHandler => {\n  const { ctx } = options\n\n  return (err: any, req: Request, res: Response, _next: NextFunction): void => {\n    ctx.error(err.message, { code: err.code, message: err.message })","sourceCodeStart":27,"sourceCodeEnd":63,"githubUrl":"https://github.com/hcengineering/platform/blob/63e28dc96483967b2fc21c881b3f1023c1de7718/pods/link-preview/src/middleware.ts#L27-L63","documentation":"withAuthorization middleware extracts a bearer/auth token from request headers. If extractToken returns null (no Authorization header, malformed scheme, etc.), it throws HttpError 401 which express passes to the error handler as 'Unauthorized'.","triggerScenarios":"Calling any link-preview endpoint without an Authorization header; header present but not in the format extractToken expects (e.g. missing 'Bearer ' prefix); empty token string.","commonSituations":"Client forgot to attach token after login; reverse proxy stripping Authorization header; frontend using different auth scheme than the middleware expects; curl tests omitting -H flag.","solutions":["Send a valid Authorization header, e.g. 'Authorization: Bearer <token>'","Check extractToken's expected header format and match it in the client","Verify no proxy/gateway strips the Authorization header"],"exampleFix":"// before\nfetch('/api/link-preview?url=...')\n// after\nfetch('/api/link-preview?url=...', { headers: { Authorization: 'Bearer ' + token } })","handlingStrategy":"validation","validationCode":"const token = localStorage.getItem('token')\nif (!token) throw new Error('Not authenticated: attach Authorization header before calling API')\n// then: headers: { Authorization: `Bearer ${token}` }","typeGuard":null,"tryCatchPattern":"try {\n  const res = await fetch(url, { headers: { Authorization: 'Bearer ' + token } })\n  return await res.json()\n} catch (err) {\n  if (res?.status === 401) { redirectToLogin(); return }\n  throw err\n}","preventionTips":["Attach the Authorization header in a shared fetch/axios interceptor","Check header format matches extractToken's expectations (scheme + token)","Ensure proxies don't strip Authorization headers","Refresh tokens before expiry"],"tags":["auth","http-401","middleware","token"],"backgroundTag":"missing-auth-token","analyzedSha":"63e28dc96483967b2fc21c881b3f1023c1de7718","analyzedAt":"2026-08-29T15:21:27.377Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}