hcengineering/platform · error · TokenError
nbf and exp are required when sub is not provided
Error message
nbf and exp are required when sub is not provided
What it means
A grant with no sub (subject) must be time-bounded: generateToken requires both nbf and exp when a grant is given but sub is omitted, so anonymous/workspace-grant tokens cannot live forever.
Source
Thrown at foundations/core/packages/token/src/token.ts:79
grant?: PermissionsGrant
nbf?: number
exp?: number
sub?: PersonUuid
}
): string {
if (!validate(accountUuid)) {
throw new TokenError(`Invalid account uuid: "${accountUuid}"`)
}
if (workspaceUuid !== undefined && !validate(workspaceUuid)) {
throw new TokenError(`Invalid workspace uuid: "${workspaceUuid}"`)
}
const { grant, nbf, exp, sub } = options ?? {}
if (grant?.workspace !== undefined && !validate(grant?.workspace)) {
throw new TokenError(`Invalid grant workspace uuid: "${grant?.workspace}"`)
}
if (grant != null && sub == null && (nbf == null || exp == null)) {
throw new TokenError('nbf and exp are required when sub is not provided')
}
const service = getMetadata(serverPlugin.metadata.Service)
if (service !== undefined) {
extra = { service, ...extra }
}
const sanitizedGrant: PermissionsGrant | undefined =
grant !== undefined
? {
workspace: grant.workspace,
role: grant.role,
grantedBy: grant.grantedBy,
firstName: grant.firstName,
lastName: grant.lastName,
spaces: grant.spaces,
extra: grant.extra
}View on GitHub (pinned to 63e28dc964)
Solutions
- Provide both nbf and exp in options when issuing a grant token without sub
- Set sub (a PersonUuid) if the token should be bound to a person instead
- Review token-issuing call sites to ensure grant tokens always have a validity window
Example fix
// before
generateToken(account, workspace, { grant: { workspace } })
// after
const now = Math.floor(Date.now() / 1000)
generateToken(account, workspace, { grant: { workspace }, nbf: now, exp: now + 3600 }) Defensive patterns
Strategy: validation
Validate before calling
if (grant != null && sub == null && (nbf == null || exp == null)) {
throw new Error('provide nbf and exp for grant tokens without sub')
} Try / catch
try {
return generateToken(account, workspace, opts)
} catch (e) {
if (e instanceof TokenError && e.message.includes('nbf and exp are required')) {
const now = Math.floor(Date.now() / 1000)
return generateToken(account, workspace, { ...opts, nbf: now, exp: now + opts.ttl ?? 3600 })
}
throw e
} Prevention
- Wrap token issuance in a helper that always injects a default validity window
- Remember sub OR (nbf+exp) is mandatory whenever a grant is present
- Set token TTLs explicitly in one shared constant
When it happens
Trigger: Calling generateToken with grant set, sub left undefined, and either nbf or exp (or both) missing from options.
Common situations: Issuing service or workspace-scoped tokens where the developer forgot expiry; migrating code that previously used sub and now omits it without adding nbf/exp.
Related errors
- Token expired
- Workspace or account not found in token
- Invalid account uuid: "${accountUuid}"
- Invalid workspace uuid: "${workspaceUuid}"
- Invalid grant workspace uuid: "${grant?.workspace}"
AI-assisted analysis of hcengineering/platform@63e28dc964 (2026-08-29).
Data as JSON: /api/errors/0727523aabc6dcea.
Report an issue: GitHub.