hcengineering/platform · error
Missing auth info
Error message
Missing auth info
What it means
withLoginInfoAsync rejects with 403 'Missing auth info' when the token exists but the account service returns null from getLoginInfoByToken — i.e. the token is unrecognized, expired, revoked, or the account service is unreachable/misbehaving such that no login info resolves.
Source
Thrown at services/payment/pod-payment/src/middleware.ts:62
return
}
next()
}
export const withLoginInfo = (req: RequestWithAuth, res: Response, next: NextFunction): void => {
void withLoginInfoAsync(req, res, next)
}
const withLoginInfoAsync = async (req: RequestWithAuth, res: Response, next: NextFunction): Promise<void> => {
if (req.token === undefined || req.token == null) {
res.status(401).json({ message: 'Token error' }).end()
return
}
const accountClient = getAccountClient(req.headers.authorization?.split(' ')[1])
const loginInfo = await accountClient.getLoginInfoByToken()
if (loginInfo == null) {
res.status(403).json({ message: 'Missing auth info' }).end()
return
}
req.loginInfo = loginInfo
next()
}
export const withOwner = (req: RequestWithAuth, res: Response, next: NextFunction): void => {
void withOwnerAsync(req, res, next)
}
const withOwnerAsync = async (req: RequestWithAuth, res: Response, next: NextFunction): Promise<void> => {
if (req.token === undefined || req.token == null) {
res.status(401).json({ message: 'Token error' }).end()
return
}
if (req.params.workspace != null && req.token.workspace !== req.params.workspace) {
res.status(401).json({ message: 'Workspace mismatch' }).end()View on GitHub (pinned to 63e28dc964)
Solutions
- Refresh the access token (re-authenticate) and retry with a valid bearer token
- Check account service availability and the getAccountClient base URL configuration in this pod
- Confirm the token was issued by the same environment's account service (issuer/audience match)
- Check for clock skew between pods if tokens are rejected immediately after issuance
Example fix
// before // client retries forever with expired token requestWithSameToken() // after if (isTokenExpired(token)) token = await refreshToken() requestWithToken(token)
Defensive patterns
Strategy: retry
Validate before calling
// client-side: check token expiry before calling
const payload = JSON.parse(atob(token.split('.')[1]))
if (payload.exp * 1000 <= Date.now()) {
token = await refreshAccessToken() // avoids 403 Missing auth info from a dead token
} Type guard
function isUsableToken(token: string | undefined): token is string {
if (!token) return false
try {
const { exp } = JSON.parse(Buffer.from(token.split('.')[1], 'base64').toString())
return typeof exp === 'number' && exp * 1000 > Date.now()
} catch { return false }
} Try / catch
try {
const res = await callApi()
} catch (err) {
if (err.response?.status === 403 && err.response.data?.message === 'Missing auth info') {
await refreshAccessToken();
// retry once, then fail; also check account-service health
}
} Prevention
- Implement proactive token refresh before expiry (or on 401/403)
- Use environment-specific tokens per account service (dev/staging/prod)
- Monitor account service health; alert on null getLoginInfoByToken spikes
- Clock-sync pods (NTP) to avoid premature token rejection
When it happens
Trigger: Expired or revoked bearer token presented to getLoginInfoByToken; token signed for a different environment/account service; account service down or returning null due to internal error; passing a malformed-but-extractable token string.
Common situations: Long-lived clients with expired JWTs that were never refreshed; tokens from a dev account service used against staging payment pod; account service outage or wrong ACCOUNT_SERVICE_URL config; clock skew invalidating freshly issued tokens.
Related errors
AI-assisted analysis of hcengineering/platform@63e28dc964 (2026-08-29).
Data as JSON: /api/errors/59fa14818bd368f0.
Report an issue: GitHub.