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" })
          return

View on GitHub (pinned to 63e28dc964)

Solutions

  1. Send the header exactly as `Authorization: Bearer <token>` where <token> equals config.AuthToken of the pod.
  2. Compare the token value in the client against the server's AuthToken env/config — re-sync rotated secrets.
  3. If auth is not intended, unset config.AuthToken on the server (the check is skipped entirely when it is undefined).
  4. 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

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.