fix(auth): keep the permission list out of access tokens (11.5 KB → <2 KB)
Merged
EV
11d ago+163+163+012345678901234567890123456789-1-1-0123456789
Why
Every request carries the access token. It embedded the name of every enabled permission of the user's role — 380 for a super admin after the platform-extensions merge (#10254) → an 11.5 KB token (11,722 B for every permission in PermissionsEnum), growing ~30 B with each new permission. On the way:
- the web image's nginx refuses header lines over 8 KB →
./assets/i18n/en.jsonanswered 400 for signed-in users (worked around in #10634 by not sending the token to static assets); - Node caps all request headers together at 16 KB (no
--max-http-header-sizeoverride in the repo) → ~3 KB of headroom for every API call, shrinking with every plugin.
Nobody reads the claim
- API:
JwtStrategy.validate()→RoleAuthorizationService.attachAuthorizationState()pins the role's current permissions from the database on each request;RequestContext.hasPermission(s)reads those ("never thepermissionsclaim"). Field visibility and GraphQL subscriptions read the request user / a live evaluator, never the token. - Web: permissions come from
/user/me(role.rolePermissions). - Desktop timer/agent, desktop-ui-lib, MCP server: decode
exp/employeeId/tenantIdonly. - Ever Teams web (
jwt-utils.ts,ever-id/session.ts) and mobile (tokenHandler.ts): the payload type listspermissions?but nothing reads it — onlyexpand ids.
Change
getJwtAccessToken()leavespermissionsout of new access tokens.- Gated, not deleted:
JWT_ACCESS_TOKEN_INCLUDE_PERMISSIONS=trueputs it back for an integration that still decodes it (access-token-claims.ts, documented in.env.sample). Tokens issued before the deploy keep working (the API never read the claim).
Evidence
- New
auth.service.access-token-size.spec.tsdrives the realgetJwtAccessToken()and signs the payload with HS256 as the scoped token service does. Red on develop77606f6199: 2 of 4 fail — claim present,Bearerheader 11,722 bytes. Green: 4/4 (no claim, < 2 KB, id/tenant/org/employee/role/exp kept, flag restores the list). - auth + request-context + role + access-token + token suites: 460/460;
tsc -p packages/core/tsconfig.lib.json --noEmit0 errors; all 35 static gates pass; cspell clean. - Boot proof (fresh SQLite, demo seed, login, permission-guarded REST + GraphQL, e2e): running — results will be posted here.
Tracked in the homelab handover HANDOVER-2026-10-15-gauzy-followups.md (Q2).
🤖 Generated with Claude Code
Summary by cubic
Shrinks access tokens by leaving the role's permission list out of new tokens — a super admin's token drops from 11.5 KB to under 2 KB.
- Each token previously embedded every enabled permission (380 for a super admin), blowing past nginx's 8 KB header-line cap and eating into Node's 16 KB total request-header budget on every API call.
- Nothing reads the claim: requests are authorized against the role's current permissions from the database, and clients load them from
/user/me. - Set
JWT_ACCESS_TOKEN_INCLUDE_PERMISSIONS=trueto restore the list for an integration that still decodes it (documented in.env.sample); already-issued tokens keep working. - Specs drive the real
getJwtAccessToken(), sign the payload with the exact claimsCreateTokenHandleradds, and verify the token stays under 2 KB while keeping theid,tenantId,organizationId,employeeId,role, andexpclaims.