Admin Endpoints

All admin endpoints require a valid admin JWT (platform admin, tenant admin, or app admin depending on the operation).

Apps

POST /admin/apps

Create a new app.

Auth: Platform admin or tenant admin

Request:

{
  "name": "My App",
  "tenant_id": "tenant-uuid",
  "bundle_id": "com.example.myapp",
  "registration_policy": "invite",
  "config": {
    "allowed_providers": ["password", "google"],
    "redirect_uris": ["https://myapp.com/auth/callback"],
    "available_roles": ["user", "manager", "admin"],
    "auto_assign_roles": ["user"],
    "token_lifetime_minutes": 15,
    "refresh_lifetime_days": 30,
    "branding": {
      "primary_color": "#9392c7",
      "logo_url": null,
      "logo_height": 80
    }
  }
}

Response (201): The created app object including id and client_secret (shown once).

PUT /admin/apps/{app_id}

Update app configuration.

Auth: Platform admin, tenant admin, or app admin (managers excluded)

Request: Partial update — only include fields to change.

{
  "name": "Updated Name",
  "config": {
    "allowed_providers": ["password", "google", "magic_link"],
    "branding": { "primary_color": "#d1001f" }
  }
}

Note: Uploaded logo_data is preserved automatically when saving config without it.

POST /admin/apps/{app_id}/logo

Upload an app logo.

Auth: Platform admin, tenant admin, or app admin

Request: Multipart form data with file field (PNG, JPEG, SVG, max 2MB, resized to 256px).

POST /admin/apps/{app_id}/regenerate-secret

Generate a new client secret. Old secret is invalidated immediately.

Auth: Platform admin, tenant admin, or app admin

Response:

{ "client_secret": "new-secret-shown-once" }

Users

GET /admin/users

List all users (platform admin only).

Query Params: ?page=1&limit=50&search=email

POST /admin/users

Create a user.

Auth: Platform admin

Request:

{
  "email": "user@example.com",
  "display_name": "Jane Doe",
  "password": "optional"
}

PUT /admin/users/{user_id}/roles

Assign roles for a user in an app.

Auth: Platform admin, tenant admin, or app admin (managers excluded)

Request:

{
  "app_id": "uuid",
  "roles": ["user", "admin"]
}

The user role is always included (enforced by ensure_base_role()).

POST /admin/users/{user_id}/suspend

Suspend a user's access to an app.

Auth: Platform admin, tenant admin, or app admin

Request:

{ "app_id": "uuid" }

DELETE /admin/users/{user_id}

Remove a user's enrollment from an app.

Auth: Platform admin, tenant admin, or app admin

Request:

{ "app_id": "uuid" }

PUT /admin/users/{user_id}/password

Change a user's password (admin override).

Auth: Platform admin only

Request:

{ "new_password": "new_secure_password" }

Password minimum length is enforced per the user's strictest tenant policy.

GET /admin/users/{user_id}/rate-limits

Check rate limit status for a user.

Auth: Platform admin only

Response:

{
  "user_id": "uuid",
  "email": "user@example.com",
  "rate_limits": [
    { "label": "Login (email)", "key": "rl:login:user@example.com", "count": 4, "ttl": 583 }
  ]
}

POST /admin/users/{user_id}/rate-limits/clear

Clear all rate limits for a user.

Auth: Platform admin only


Invites

POST /admin/apps/{app_id}/invites

Create and optionally send an invite.

Auth: Platform admin, tenant admin, app admin, or app manager (managers restricted to user role only)

Request:

{
  "app_id": "uuid",
  "roles": ["user"],
  "send_to_email": "invitee@example.com",
  "max_uses": 1,
  "expires_days": 7
}

Response:

{
  "code": "ABCD1234",
  "app_id": "uuid",
  "roles": ["user"],
  "expires_at": "2026-03-24T00:00:00Z",
  "email_sent": true
}

Tenant Admin Management

POST /admin/tenants/{tenant_id}/admins

Invite a new tenant admin.

Auth: Platform admin or existing tenant admin for this tenant

Request:

{
  "email": "newadmin@example.com"
}

DELETE /admin/tenants/{tenant_id}/admins/{user_id}

Remove a tenant admin. Cannot remove yourself.

Auth: Platform admin or existing tenant admin for this tenant