hcengineering/platform · error

Token error

Error message

Token error

What it means

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.

Source

Thrown at services/payment/pod-payment/src/middleware.ts:30

// See the License for the specific language governing permissions and
// limitations under the License.
//

import type { NextFunction, Request, Response } from 'express'
import { extractToken, getAccountClient } from '@hcengineering/server-client'
import { AccountRole, systemAccountUuid } from '@hcengineering/core'
import { Token } from '@hcengineering/server-token'
import type { LoginInfo, LoginInfoRequest, WorkspaceLoginInfo } from '@hcengineering/account-client'

export interface RequestWithAuth extends Request {
  token?: Token
  loginInfo?: LoginInfo | WorkspaceLoginInfo | LoginInfoRequest
}

export const withToken = (req: RequestWithAuth, res: Response, next: NextFunction): void => {
  const token = extractToken(req.headers)
  if (token === undefined || token == null) {
    res.status(401).json({ message: 'Token error' }).end()
    return
  }
  req.token = token
  next()
}

export const withAdmin = (req: RequestWithAuth, res: Response, next: NextFunction): void => {
  if (req.token === undefined || req.token == null) {
    res.status(401).json({ message: 'Token error' }).end()
    return
  }
  if (req.token.account !== systemAccountUuid && req.token.extra?.admin !== 'true') {
    res.status(401).json({ message: 'Admins only' }).end()
    return
  }
  next()
}

View on GitHub (pinned to 63e28dc964)

Solutions

  1. Add a valid 'Authorization: Bearer <token>' header to the request
  2. Verify the client library actually sends headers (e.g. set headers in axios defaults/fetch options) and no proxy strips them
  3. Confirm the request goes through the correct gateway/base URL that expects this auth scheme
  4. If token extraction should support other header names, update extractToken in middleware.ts

Example fix

// before
await fetch('https://api.example.com/payment/orders')
// after
await fetch('https://api.example.com/payment/orders', {
  headers: { Authorization: `Bearer ${accessToken}` }
})
Defensive patterns

Strategy: validation

Validate before calling

const authHeader = headers['authorization'] ?? ''
if (!authHeader.startsWith('Bearer ') || authHeader.length <= 'Bearer '.length) {
  throw new Error('Request would fail: no bearer token in Authorization header')
}

Type guard

function hasToken(headers: IncomingHttpHeaders): boolean {
  const h = headers['authorization']
  return typeof h === 'string' && h.startsWith('Bearer ') && h.slice(7).length > 0
}

Try / catch

try {
  const res = await callApi()
} catch (err) {
  if (err.response?.status === 401 && err.response.data?.message === 'Token error') {
    // re-authenticate and attach token before retrying
  }
}

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Related errors


AI-assisted analysis of hcengineering/platform@63e28dc964 (2026-08-29). Data as JSON: /api/errors/71f14a7e67dc62b2. Report an issue: GitHub.