{"record":{"id":"c1d687f2e2397d87","repo":"hcengineering/platform","slug":"invalid-auth-token","errorCode":null,"errorMessage":"Invalid auth token","messagePattern":"Invalid auth token","errorType":"http","errorClass":null,"httpStatus":401,"severity":"error","filePath":"services/notification/pod-notification/src/main.ts","lineNumber":52,"sourceCode":"        publicKeyLen: config.PushPublicKey.length,\n        privateKeyLen: config.PushPrivateKey.length\n      })\n      webpush.setVapidDetails(subj, config.PushPublicKey, config.PushPrivateKey)\n      webpushInitDone = true\n    } catch (err: unknown) {\n      ctx.error('Failed to set VAPID details', { error: err })\n    }\n  } else {\n    ctx.warn('VAPID keys not configured; /web-push will return empty results until keys are set')\n  }\n\n  const checkAuth = (req: Request<any>, res: Response<any>): boolean => {\n    if (config.AuthToken !== undefined) {\n      // We need to verify authorization\n      const authorization = req.headers.authorization ?? ''\n      const token = authorization.replace('Bearer ', '')\n      if (token !== config.AuthToken) {\n        res.status(401).send({ err: 'Invalid auth token' })\n        return false\n      }\n    }\n    return true\n  }\n\n  const endpoints: Endpoint[] = [\n    {\n      endpoint: '/web-push',\n      type: 'post',\n      handler: async (req, res) => {\n        if (!checkAuth(req, res)) {\n          return\n        }\n        const data: PushData | undefined = req.body?.data\n        if (data === undefined) {\n          res.status(400).send({ err: \"'data' is missing\" })\n          return","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/hcengineering/platform/blob/63e28dc96483967b2fc21c881b3f1023c1de7718/services/notification/pod-notification/src/main.ts#L34-L70","documentation":"The pod-notification service verifies a Bearer token in the Authorization header against config.AuthToken and responds HTTP 401 { err: 'Invalid auth token' } on mismatch. Verification only runs when AuthToken is configured; the header (after stripping the 'Bearer ' prefix) must exactly equal the configured token. Missing header, wrong prefix, or wrong secret all produce this error.","triggerScenarios":"POST to a notification endpoint without an Authorization header, with a header not using the 'Bearer <token>' form, with an outdated/rotated token, or with a token from a different environment's config.","commonSituations":"AuthToken configured on the server but the client was never told (common after enabling auth); token rotation in secret managers not propagated to clients; whitespace/case mistakes ('bearer' vs 'Bearer' — the code replaces the literal 'Bearer '); calling the pod from another service whose env var holds a different value.","solutions":["Send the header exactly as `Authorization: Bearer <token>` where <token> equals config.AuthToken of the pod.","Compare the token value in the client against the server's AuthToken env/config — re-sync rotated secrets.","If auth is not intended, unset config.AuthToken on the server (the check is skipped entirely when it is undefined).","Beware trailing whitespace/newlines in the token from env files or secret stores; trim before sending."],"exampleFix":"// before\nawait fetch(url, { method: 'POST', body })\n// after\nawait fetch(url, { method: 'POST', headers: { Authorization: `Bearer ${process.env.NOTIFY_TOKEN.trim()}` }, body })","handlingStrategy":"validation","validationCode":"const token = process.env.NOTIFY_TOKEN\nif (!token) throw new Error('NOTIFY_TOKEN not configured on client')\nconst headers = { Authorization: `Bearer ${token.trim()}` }","typeGuard":"const hasBearer = (h: Record<string, string>): boolean => /^Bearer \\S+$/.test(h.Authorization ?? '')","tryCatchPattern":"const res = await fetch(url, { headers, ...opts })\nif (res.status === 401) throw new Error('Invalid auth token: re-sync client token with pod config.AuthToken')","preventionTips":["Read the token from one shared secret store so client and server stay in sync","Always use the exact 'Bearer ' prefix (capital B, single space)","Trim tokens to strip whitespace from env files and secret managers","Rotate tokens simultaneously on client and server"],"tags":["http-401","authentication","bearer-token","authorization"],"backgroundTag":"invalid-auth-token","analyzedSha":"63e28dc96483967b2fc21c881b3f1023c1de7718","analyzedAt":"2026-08-29T15:21:27.377Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}