5.1 The auth service: login, refresh, logout, current user
auth provides identity for a tenant: it turns credentials into a token, and the
runtime checks that token (and the roles it carries) on every request. This
section covers the endpoints; the next two cover users/roles and how mounts use
them.
Enabling auth
Two things turn auth on for a tenant:
A tenant-level
authobject with a signing key:"auth": { "jwtSecret": "<required>", "sessionMinutes": 60, "maxAttempts": 5, "lockMinutes": 10, "userDataset": "users", "jwtUserProps": ["accountId"] }An
authmount (conventionally at/auth):{ "path": "/auth", "service": "auth", "config": { "access": { "read": "authenticated", "invoke": "all" } } }
Once auth.jwtSecret is set, the runtime verifies a presented token on every
request to the tenant — not just the auth mount.
The endpoints
| Endpoint | Does |
|---|---|
POST /auth/login {email, password} |
→ 200 {token, exp} and a Set-Cookie: rs-auth=… (HttpOnly). Failures are a uniform 401 (no user enumeration); after maxAttempts failures the account locks for lockMinutes (401 + Retry-After) |
POST /auth/refresh |
With a valid token past 50% of its lifetime, issues a fresh one; earlier than that, echoes the current token |
POST /auth/logout |
→ 204, clears the cookie |
GET /auth/user |
→ the verified principal {id, roles, kind, …extra claims} (401 if anonymous) |
Logging in
$r = Invoke-RestMethod -Method Post -Uri "http://127.0.0.1:3100/auth/login" `
-ContentType "application/json" `
-Body (@{ email = "ada@example.com"; password = $pw } | ConvertTo-Json)
$token = $r.token
You then authenticate subsequent requests with either the cookie (browsers get it automatically) or a bearer header:
Authorization: Bearer <token>
Keep the login mount reachable
Login and refresh are POSTs, so read doesn't gate them — they map to invoke.
Make sure the auth mount's access doesn't lock out invoke. The simplest safe
posture is invoke: "all" so anyone can attempt to log in; the credentials
themselves are the gate. Do not omit access: an absent policy fails closed.
Bootstrapping the first operator
The first operator is a deliberate root-of-trust step: they cannot be created
through an API that already requires an operator. On a fresh node whose
/services mount is temporarily open, the CLI can do the whole sequence:
rs2 auth init --admin-email admin@example.com
It enables auth, creates the first admin with a locally generated argon2id hash,
logs in, and locks down the user store and /services. Keep the node bound to
127.0.0.1 during this short bootstrap window. Operators can instead seed one
user at server startup with bootstrapAdmin (10.7).
jwtUserProps optionally copies named user-record fields into the JWT and the
principal returned by /auth/user. Those claims are also available to pipeline
path rules and transforms. Treat them as authority for the token's lifetime:
only copy fields that users cannot edit themselves.
A subtlety worth knowing now
Because the runtime verifies any presented token, an invalid or expired
token is 401 even on an open mount that would otherwise accept anonymous
callers. The fix is to strip a bad token and retry anonymously, not to resend
it. (More on this in 5.3.)
Next: the users and roles those tokens represent.
← Previous: 5.0 The RS2 security model · Manual home · Next: 5.2 Users, password hashes, roles →