App user auth
Covers the 6 API operations in the app-auth category.
| Method | Path | Description |
|---|---|---|
| GET | /v1/orgs/{orgSlug}/projects/{projectName}/auth | End-user auth status (runlot auth) |
| POST | /v1/orgs/{orgSlug}/projects/{projectName}/auth | Turn auth on (runlot deploy calls this after reading the "auth": true declaration) |
| PATCH | /v1/orgs/{orgSlug}/projects/{projectName}/auth | Update the settings (runlot auth set) |
| DELETE | /v1/orgs/{orgSlug}/projects/{projectName}/auth | Turn auth off (runlot auth delete) |
| PUT | /v1/orgs/{orgSlug}/projects/{projectName}/auth/providers/{provider} | Register or replace a social provider (runlot auth provider set) |
| DELETE | /v1/orgs/{orgSlug}/projects/{projectName}/auth/providers/{provider} | Disconnect a login provider (runlot auth provider rm) |
GET /v1/orgs/{orgSlug}/projects/{projectName}/auth
Whether auth is granted, the settings, the registered providers, and the hosts to hang callbacks on (docs/auth.md §9).
The subscriber table is not part of this API. User records live in the runlot_auth schema of the project's Postgres (docs/auth.md §6), and CP does not query those tables. You can inspect the current user list from the worker's env.auth.users.* and from runlot pg shell.
providers carries the client id only. The client secret is sealed and never leaves in any response (the rule for secret surfaces).
Requires viewer or above — "does this app have login" is a fact anyone in the organization needs to know.
operationId getAuth
| Status | Description | Response body |
|---|---|---|
| 200 | Auth status | AuthStatus |
| 403 | — | — |
| 404 | — | — |
| 503 | no_core — no cp-core connection | Error |
POST /v1/orgs/{orgSlug}/projects/{projectName}/auth
Idempotent — calling it twice leaves the settings and the login providers unchanged. Because the record's existence is the only expression of being enabled (migration 0024), there is no "on but off" state.
A database must exist. Otherwise it returns 409 database_required. The user table lives inside the project DB (docs/auth.md §1), so enabling auth alone leaves the worker without its tables at startup. This is why the "auth": true declaration also turns on the database, and since the deploy grants in that order it never sees this 409.
Once enabling completes, the node starts the auth system worker as the socket's entry service at the next convergence. As with env.db and env.storage, no redeploy is needed. Table initialization is idempotent, so turning it on twice runs it once.
There is no request body. The settings start at their defaults (the defaults of AuthSettings); changing them is a PATCH.
Requires member or above. Audit event auth.grant.
operationId grantAuth
| Status | Description | Response body |
|---|---|---|
| 200 | Grant status (the existing values if it already existed) | AuthStatus |
| 403 | — | — |
| 404 | — | — |
| 409 | database_required — this project has no database. Add "database": true to runlot.json and deploy. | Error |
| 503 | no_core | Error |
PATCH /v1/orgs/{orgSlug}/projects/{projectName}/auth
A partial update. Only the fields you send change; the rest stay as they were. If the screen sent all three brand settings every time one switch is flipped, a later save could overwrite an earlier one when two users edit the same settings.
If auth is not enabled it returns 404 not_granted. You cannot store settings ahead of time, because the settings are stored on the grant record itself.
sessionDays is also the setting that determines the size of the session table (docs/auth.md §13 — it stays within the 150 MB cap).
Requires member or above. Audit event auth.settings.
operationId updateAuthSettings
Request body: application/json · AuthSettingsPatch
| Status | Description | Response body |
|---|---|---|
| 200 | The updated status | AuthStatus |
| 400 | — | — |
| 403 | — | — |
| 404 | not_granted — this project has no auth. When the project itself does not exist the code is not_found, not this one. | Error |
| 503 | no_core | Error |
DELETE /v1/orgs/{orgSlug}/projects/{projectName}/auth
Subscriber data is not deleted. The runlot_auth tables stay in the project DB (docs/auth.md §9) — the data belongs to the DB, and deleting it is runlot pg's job. Turn auth back on and the same people log in as before.
From the next convergence the auth system worker goes down and /__runlot/auth/* passes straight through to the user worker — if there is no route at that path, it is a 404.
Turning it off is idempotent too. It returns 204 even when auth was never enabled.
Requires admin or above — turning it on is a member's call, but turning it off signs out everyone who is logged in. Audit event auth.revoke.
operationId revokeAuth
| Status | Description | Response body |
|---|---|---|
| 204 | Revoked | — |
| 403 | — | — |
| 404 | — | — |
| 503 | no_core | Error |
PUT /v1/orgs/{orgSlug}/projects/{projectName}/auth/providers/{provider}
Each project registers its own OAuth app. There is no shared platform app because the consent screen, the review and the privacy terms all belong to the owner of that app (docs/auth.md §12).
The callback URL to register with the provider is https://<host>/__runlot/auth/callback/<provider> for each host. The host list is in AuthStatus.hosts.
clientSecret is sealed with the same DEK and the same AAD as project_secrets (its name uses the reserved prefix auth/<provider>), and never comes back in any response. Replacing it is the same PUT — it is idempotent, so a retry is safe.
Requires admin or above — these are credentials. Audit event auth.provider.set (the secret is not recorded).
operationId setAuthProvider
Request body: application/json · AuthProviderPut
| Status | Description | Response body |
|---|---|---|
| 200 | The updated status | AuthStatus |
| 400 | invalid_provider — the name is outside github·google·kakao, or clientId·clientSecret is empty. | Error |
| 403 | — | — |
| 404 | — | — |
| 503 | no_core | Error |
DELETE /v1/orgs/{orgSlug}/projects/{projectName}/auth/providers/{provider}
Anyone who used only that login provider can no longer log in. The user record stays and only the matching entry in identities is removed. Register it again and they log in to the same account.
Deleting a login provider that does not exist also returns 204.
Requires admin or above. Audit event auth.provider.delete.
operationId deleteAuthProvider
| Status | Description | Response body |
|---|---|---|
| 204 | Revoked | — |
| 403 | — | — |
| 404 | — | — |
| 503 | no_core | Error |