API Keys
Server-to-server and programmatic access via public/private key pairs.
For machine-to-machine auth — CLIs, integrations, internal tooling — Nest Auth ships an API key system. Each key is a pair: a non-secret public ID and a secret private value. The pair is bound to a user; calls authenticated with the key act as that user.
How calls authenticate
NestAuthAuthGuard reads the scheme: Bearer is a JWT, ApiKey is a key pair (public and private joined by a dot).
Generating a key
privateKey is returned only once, at creation. After that the library holds only a hash.
Lifecycle
| Operation | Method |
|---|---|
| Create | createAccessKey(userId, name, { tenantId? }) |
| List for user | getUserAccessKeys(userId) |
| Set expiry | setAccessKeyExpiry(publicKey, expiresAt) |
| Deactivate | deactivateAccessKey(publicKey) (key still exists, but rejects auth) |
| Delete | deleteAccessKey(publicKey) |
Lifecycle operations emit NestAuthEvents.ACCESS_KEY_* events — wire them to your audit log.
What a key request looks like to your app
Since 2.13, a request authenticated by key carries a session for the key's user, built fresh for that request. So RequestContext.currentUserId(), currentTenantId(), currentUserAccess() and request.session.data work exactly as they do for a signed-in user, and your own guards and services can tenant-scope a key request without special-casing it.
That session is never stored: it has no id, it is rebuilt from the live rows on every request (so it cannot go stale), and it cannot be refreshed, switched or logged out. Endpoints that change a stored session (logout, switch-tenant, MFA) treat a key request as having no session.
Which tenant
| Key | User's active memberships | tenantId |
|---|---|---|
Pinned ({ tenantId } at creation) | — | the pinned tenant |
| Unpinned | exactly one | that membership's tenant |
| Unpinned | several | null — pin the key to choose one |
In ISOLATED mode every user has exactly one membership, so an unpinned key is always scoped. In SHARED mode, pin keys for users who belong to more than one tenant. A key can only be pinned to a tenant its user is an active member of (400 API_KEY_TENANT_MISMATCH otherwise).
Roles & permissions
A key acts with the roles of that one membership — the same rows sign-in reads — and only while the membership is active. A pinned key whose membership has been deactivated keeps its tenant but carries no grants. (An unpinned key for a multi-tenant user still gets the union of roles across its active memberships, as before.)
A key also stops working when its owner is deactivated (401 ACCOUNT_INACTIVE), not only when the key itself is.
Turning API keys off
The guard then rejects every ApiKey credential with 401 API_KEY_AUTH_DISABLED (optional-auth routes proceed unauthenticated), and createAccessKey refuses to mint new keys. Default is true.
Key validation flow
- Guard checks
accessKeys.enabled, then parsesAuthorization: ApiKey <publicKey>.<privateKey>. - Looks up
nest_auth_access_keysbypublicKey; checksisActiveandexpiresAt. - Compares the hash of the supplied private key against the stored hash (constant-time).
- Checks the owning user is active.
- Updates
lastUsedAtand builds the request's session.
A bad key returns 401 INVALID_API_KEY.
Related
- Backend services reference —
AccessKeyService. - Request context.
- Admin console.