hcengineering/platform · error
Invalid auth token
Error message
Invalid auth token
What it means
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.
Source
Thrown at services/notification/pod-notification/src/main.ts:52
publicKeyLen: config.PushPublicKey.length,
privateKeyLen: config.PushPrivateKey.length
})
webpush.setVapidDetails(subj, config.PushPublicKey, config.PushPrivateKey)
webpushInitDone = true
} catch (err: unknown) {
ctx.error('Failed to set VAPID details', { error: err })
}
} else {
ctx.warn('VAPID keys not configured; /web-push will return empty results until keys are set')
}
const checkAuth = (req: Request<any>, res: Response<any>): boolean => {
if (config.AuthToken !== undefined) {
// We need to verify authorization
const authorization = req.headers.authorization ?? ''
const token = authorization.replace('Bearer ', '')
if (token !== config.AuthToken) {
res.status(401).send({ err: 'Invalid auth token' })
return false
}
}
return true
}
const endpoints: Endpoint[] = [
{
endpoint: '/web-push',
type: 'post',
handler: async (req, res) => {
if (!checkAuth(req, res)) {
return
}
const data: PushData | undefined = req.body?.data
if (data === undefined) {
res.status(400).send({ err: "'data' is missing" })
returnView on GitHub (pinned to 63e28dc964)
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.
Example fix
// before
await fetch(url, { method: 'POST', body })
// after
await fetch(url, { method: 'POST', headers: { Authorization: `Bearer ${process.env.NOTIFY_TOKEN.trim()}` }, body }) Defensive patterns
Strategy: validation
Validate before calling
const token = process.env.NOTIFY_TOKEN
if (!token) throw new Error('NOTIFY_TOKEN not configured on client')
const headers = { Authorization: `Bearer ${token.trim()}` } Type guard
const hasBearer = (h: Record<string, string>): boolean => /^Bearer \S+$/.test(h.Authorization ?? '')
Try / catch
const res = await fetch(url, { headers, ...opts })
if (res.status === 401) throw new Error('Invalid auth token: re-sync client token with pod config.AuthToken') Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
AI-assisted analysis of hcengineering/platform@63e28dc964 (2026-08-29).
Data as JSON: /api/errors/c1d687f2e2397d87.
Report an issue: GitHub.