Skip to main content

Auth API

Session (JWT)

Register

POST /api/v1/auth/register

Create a new user account.

Body: {email, password, name?}

Returns: {user: {id, email, name}, token, refresh_token}


Login

POST /api/v1/auth/login

Body: {email, password}

Returns: {user: {id, email, name}, token, refresh_token}


Logout

POST /api/v1/auth/logout

Invalidates the current session. Requires Authorization: Bearer <token>.


Refresh

POST /api/v1/auth/refresh

Exchange a refresh token for a new access token.

Body: {refresh_token}

Returns: {token, refresh_token}


User profile

Get current user

GET /api/v1/users/me

Requires auth. Returns the authenticated user's profile.


Get user profile

GET /api/v1/users/{userID}

Requires auth.


Update profile

PUT /api/v1/users/{userID}

Body: {name?, email?}


Get own permissions

GET /api/v1/permissions

Returns the authenticated user's permissions across all repositories and the system domain. Used by the frontend RBAC store.


Admin (role management)

List users

GET /api/v1/admin/users

Permission: user:read. Returns all users.


Assign role

PUT /api/v1/admin/users/roles

Permission: role:manage.

Body: {user_id, role, domain}


Remove role

DELETE /api/v1/admin/users/roles

Permission: role:manage.

Body: {user_id, role, domain}


List permissions

GET /api/v1/admin/permissions

Permission: role:read. Returns all known permissions and their roles.


OAuth 2.1 Endpoints

These are the endpoints an MCP client or programmatic agent uses to obtain access tokens. The server implements OAuth 2.1 with PKCE.

Register client

POST /api/v1/oauth/register

Register an OAuth 2.1 client (typically a "public" client with PKCE). Returns the client credentials.


Authorize

GET /api/v1/oauth/authorize POST /api/v1/oauth/authorize

The authorization endpoint. The GET returns a server-rendered login + consent HTML page; the POST submits the authorization decision.


Authorize login

POST /api/v1/oauth/authorize/login

Server-rendered login form submission for the OAuth flow.


Token

POST /api/v1/oauth/token

Exchange an authorization code (with PKCE verification) for an access + refresh token. Access tokens are HS256 JWTs.


Revoke

POST /api/v1/oauth/revoke

Revoke a refresh token. Refresh tokens are hashed at rest in okt_system.oauth_refresh_tokens.


Well-known

Authorization server metadata

GET /.well-known/oauth-authorization-server

Returns the OAuth 2.1 authorization server metadata (issuer, endpoints, supported scopes, etc.).


Protected resource metadata

GET /.well-known/oauth-protected-resource

Returns the protected resource metadata.


Bootstrap admin

There are two ways to get a sysadmin on a fresh install — pick one based on whether the deployment is reachable from the public internet.

First-user autopromotion (default, localhost dev)

bootstrap.auto_promote_first_user (default true) makes the first successful POST /api/v1/auth/register on an empty users table grant the sysadmin role on the system domain to that user. So:

  1. docker compose up
  2. Open http://localhost:3000 and register.
  3. You're sysadmin. Done — no env vars, no scripts.

Bindable from .env via OKT_BOOTSTRAP_AUTO_PROMOTE (accepts true/false/1/0). A log line is emitted when it fires so an operator notices if it fires unexpectedly.

Explicit admin from env vars (public deployments)

For a publicly-exposed deployment, set OKT_BOOTSTRAP_AUTO_PROMOTE=false in .env and use the default_admin flag + the OKT_BOOTSTRAP_DEFAULT_ADMIN_* env vars so an attacker cannot become sysadmin by registering first:

bootstrap:
auto_promote_first_user: false
default_admin: true
OKT_BOOTSTRAP_DEFAULT_ADMIN_EMAIL=[email protected]
OKT_BOOTSTRAP_DEFAULT_ADMIN_PASSWORD= # generate a strong one
OKT_BOOTSTRAP_DEFAULT_ADMIN_DISPLAY_NAME=Default Admin

The admin is seeded at boot (bootstrap.EnsureDefaultAdmin) when the users table is empty. Once any user exists, the step is a no-op (the env vars may be removed or rotated safely).

When both auto_promote_first_user and default_admin are enabled, default_admin wins: it runs at boot before any Register call, so the users table is non-empty by the time autopromote's CountUsers() == 1 guard would fire.

Promoting an existing user (dev only)

To promote an already-registered user to system admin (sysadmin role on the system domain, giving */*):

just bootstrap-admin [email protected]

This is idempotent and restarts the dev API service so the in-memory enforcer reloads. It targets the dev compose profile (backend/docker-compose.yml --profile dev); there is no production-stack equivalent short of psql surgery or having an existing admin call PUT /api/v1/admin/users/roles. See Operator guide.