Admin
Privileged administrative endpoints for managing organizations (orgs) and
their local users (CRUD), versioned under /v1/admin. Authenticated by a
Bearer access token: every operation enforces its declared nauthera.*
scope (via the oauth2 security scheme) IN ADDITION to the permission it
declares in x-permission, which the caller's roles must grant. Organization
endpoints are main-org only; user and audit endpoints are confined to the
caller's own org unless a platform role held in the main org admits them to
every org. All list endpoints use opaque
cursor (keyset) pagination — bound the page with limit, order it with
sort (per-endpoint x-sort-fields), then pass the previous response's
page.next_cursor back as cursor for as long as page.has_more is true.
Not part of the OAuth2/OIDC wire protocol.
Endpoints
- List organizations (admin, platform staff)GET
/v1/admin/orgsReturns one page of organizations (orgs) using opaque cursor (keyset) pagination. Bound the page size with limit and choose an ordering with sort (see x-sort-fields for what this endpoint accepts; the org id is appended so the ordering is total). Then walk the listing by passing the previous response's page.next_cursor back as cursor for as long as page.has_more is true. Defaults to id order, which for this server's time-ordered ids is creation order; display_name orders by the name case-insensitively. q narrows the listing to the organizations whose slug or display name starts with it, case-insensitively; a cursor carries the search it was issued for. Requires the nauthera.orgs:read scope and the orgs.read permission held through a platform role in the main org: the listing spans every organization, so a tenant's members, who hold orgs.read for their own organization, are refused. - Create an organization (admin, main-only)POST
/v1/admin/orgsCreates a new organization (org): generates its ES256 signing key, registers it in the runtime registry, and provisions its admin clients. The one-time admin M2M client secret is returned in the response. Requires the orgs.write permission, which only a platform role held in the main org grants. - Get an organization (admin)GET
/v1/admin/orgs/{slug}Returns one organization by slug. Requires the nauthera.orgs:read scope and the orgs.read permission. A caller holding it in an organization reads that organization; reading any other takes a platform role held in the main org. Any other organization is refused with the same 403 as one that does not exist, so the answer confirms nothing about which slugs are taken; only platform staff are told 404 for a slug nobody holds. - Update an organization (admin, main-only)PATCH
/v1/admin/orgs/{slug}Changes the settings of an organization that may change after creation: the display name, FAPI mode and the verified-address requirement. Requires the orgs.write permission, which only a platform role held in the main org grants. - Delete an organization (admin, main-only)DEL
/v1/admin/orgs/{slug}Deletes an organization by slug (idempotent: deleting an unknown slug is a 204). The main org cannot be deleted. Requires the orgs.write permission, which only a platform role held in the main org grants. - Get an organization's dashboard theme (admin)GET
/v1/admin/orgs/{slug}/themeReturns the theme the admin dashboard wears for one organization: the reduced subset of its default branding with its admin console client's branding document laid over it (see DashboardTheme). Requires the nauthera.orgs:read scope and the orgs.read permission, admitted as reading the organization is: a member reads their own organization's theme, and platform staff any organization's. Any other organization is refused with the same 403 as one that does not exist. The theme is no secret — the dashboard's shell carries it before anyone signs in — but it is read here because it belongs to the admin API. Its entity tag names the theme by its content, so a caller holding it asks with If-None-Match and is answered 304 while it is current; like every admin response it is never stored by HTTP caches. - Get an organization's email relay (admin)GET
/v1/admin/orgs/{slug}/mailReturns the SMTP relay the organization's email is sent through, read-only: its own (configured in the deployment, Helm mailOrganizations), the deployment's when it has none, or none. Reports whether credentials are configured but never reads or returns them. Requires the nauthera.orgs:read scope and the orgs.read permission, admitted as reading the organization is. - Send a test email through an organization's relay (admin)POST
/v1/admin/orgs/{slug}/mail/testSends a test message through the organization's relay, now rather than through the delivery queue, to the calling administrator's own email address — never to an address in the request, so this cannot mail anyone else — and reports what the relay answered. A relay that refuses is a result (delivered: false with the stage and reply), not an error of this operation. An organization with no relay, or a caller with no email address, is refused with 409. Requires the nauthera.orgs:write scope and the orgs.write permission. - Count an organization's users, sessions and clients (admin)GET
/v1/admin/orgs/{slug}/snapshotReturns how many users slug's organization holds in total, how many were created in the window, how many are locked, suspended or blocked now, how many hold an active second factor, how many never signed in and how many are dormant; how many sessions are live; how many clients it holds by type, token endpoint authentication method and source; and how recently its users last signed in, bucketed by a day, a week, a month and a quarter. Everything is a count: no user, session or client is named. The lists are the drill-down, under their own permissions. - List an organization's OIDC clients (admin)GET
/v1/admin/orgs/{slug}/clientsReturns one page of the OIDC clients that belong to slug's organization, using opaque cursor (keyset) pagination. Bound the page size with limit and choose an ordering with sort (see x-sort-fields for what this endpoint accepts; the registration id is appended so the ordering is total). Then walk the listing by passing the previous response's page.next_cursor back as cursor for as long as page.has_more is true; page.prev_cursor steps back the same way. Defaults to client id order; display_name orders by the name case-insensitively. - Get one OIDC client's registered configuration (admin)GET
/v1/admin/orgs/{slug}/clients/{id}Returns the registered configuration of one of slug's organization's OIDC clients, named by its registration id: its redirect and logout addresses, scopes, grant and response types, how it authenticates, its PKCE policy, token lifetimes and signing algorithms, how it came to be registered, and the labels the organization may see. A client of another organization is answered as 404, exactly like an id that does not exist. - Count one OIDC client's daily, monthly and all-time users (admin)GET
/v1/admin/orgs/{slug}/clients/{id}/usageReturns how many distinct users obtained a token for one of slug's organization's OIDC clients, named by its registration id: in the last 24 hours (daily_users), the last 30 days (monthly_users) and since counting began (all_time_users). A client of another organization is answered as 404, exactly like an id that does not exist. - List an organization's identity providers (admin)GET
/v1/admin/orgs/{slug}/identity-providersReturns every external OpenID Connect provider slug's organization lets its users sign in through, ordered by provider slug. Providers are declared by an operator through the control plane, so an organization holds a handful and the list is not paged; nothing here changes one. - List users (admin)GET
/v1/admin/orgs/{slug}/usersReturns one page of local users using opaque cursor (keyset) pagination. Bound the page size with limit and choose an ordering with sort (see x-sort-fields for what this endpoint accepts; the user id is appended so the ordering is total). Then walk the listing by passing the previous response's page.next_cursor back as cursor for as long as page.has_more is true; page.prev_cursor steps back the same way. Defaults to id order, which for this server's time-ordered ids is creation order. Requires the nauthera.users:read scope and the users.read permission; the listing is confined to slug's organization. Password hashes are never returned. - Create a user (admin)POST
/v1/admin/orgs/{slug}/usersCreates a local user in slug's organization, hashing the password under THAT organization's password-hashing policy. Requires the users.create permission. username defaults to the lowercased email when omitted. - Get a user (admin)GET
/v1/admin/orgs/{slug}/users/{id}Returns one user by id. Requires the users.read permission. The id must belong to slug's organization; one that belongs to another is answered as 404, exactly like an id that does not exist. - Update a user (admin)PATCH
/v1/admin/orgs/{slug}/users/{id}Partially updates a user: any of email, username, attributes. Omitted fields are left unchanged; attributes, when present, REPLACES the whole stored map. The password is not changed here (use the password sub-resource). Requires the users.update permission. The id must belong to slug's organization; one that belongs to another is answered as 404, exactly like an id that does not exist. A change of email or username is refused 403 protected_account for the caller's own account and for an account that is more privileged than the caller; a privileged account needs a caller holding roles.assign as well. - Delete a user (admin)DEL
/v1/admin/orgs/{slug}/users/{id}Deletes a user and cascades to their sessions, MFA factors, recovery codes and pending-auth handles. Idempotent: deleting an unknown id returns 204, as does an id belonging to an organization other than slug's. Requires the users.delete permission. Refused 403 protected_account for the caller's own account and for an account that is more privileged than the caller; a privileged account needs a caller holding roles.assign as well. - Set a user's password (admin)PUT
/v1/admin/orgs/{slug}/users/{id}/passwordReplaces the user's password with a fresh hash, derived under the password-hashing policy of slug's organization, and revokes the target's existing sessions. Requires the users.credentials permission. The id must belong to slug's organization; one that belongs to another is answered as 404, exactly like an id that does not exist. Refused 403 protected_account for the caller's own account and for an account that is more privileged than the caller; a privileged account needs a caller holding roles.assign as well. - Send a user a new invitation (admin)POST
/v1/admin/orgs/{slug}/users/{id}/invitationEmails a user who has no password yet a new single-use link to choose one, as creating them with invite did. Earlier links keep working until they expire or one of them is accepted. Requires the users.create permission. The id must belong to slug's organization; one that belongs to another is answered as 404, exactly like an id that does not exist. Refused 409 conflict when the user already has a password, 409 mail_relay_missing when the organization has no email relay, and 429 too_many_requests once the user was sent auth.invitation.max_requests links within auth.invitation.validity. - List a user's known browsers and networks (admin)GET
/v1/admin/orgs/{slug}/users/{id}/devicesReturns the browsers and networks the user signed in from within the server's retention, most recently seen first: what a new-sign-in alert compares a sign-in with. A browser is named by the browser and system its user agent described and a network by its range; both are personal data, so a caller without the users.pii.read permission receives the list without them and withheld is true. - List the identity provider accounts linked to a user (admin)GET
/v1/admin/orgs/{slug}/users/{id}/identitiesReturns the upstream accounts that sign in as the user through the organization's identity providers, oldest link first. Each names the provider it was made through and the issuer that assigned its subject; active is false once the provider was deleted, or re-pointed at another issuer, so the link no longer signs anyone in. The subject is the user's personal data, so a caller without the users.pii.read permission receives the list without it and withheld is true. - List a user's roles (admin)GET
/v1/admin/orgs/{slug}/users/{id}/rolesReturns the roles the user holds in slug's organization, in role order, and the roles the caller may grant to or revoke from them. Requires the roles.read permission. The id must belong to slug's organization; one that belongs to another is answered as 404, exactly like an id that does not exist. - Grant a user a role (admin)PUT
/v1/admin/orgs/{slug}/users/{id}/roles/{role}Grants the user role in slug's organization; a role already held is answered 204 with nothing changed. Requires the roles.assign permission and a recent sign-in, and grants every role the caller's own roles cover, the owner tier included. Refused 403 protected_account for the caller's own account, for a platform role outside the main organization, where it would grant nothing, and for a role that grants a permission or platform reach the caller does not hold. The id must belong to slug's organization; one that belongs to another is answered as 404, exactly like an id that does not exist. - Revoke a user's role (admin)DEL
/v1/admin/orgs/{slug}/users/{id}/roles/{role}Takes role from the user in slug's organization; a role not held is answered 204 with nothing changed. Requires the roles.assign permission and a recent sign-in, and the same bounds as granting, so never one of the caller's own. Refused 409 last_role_administrator when the user is the organization's last active account holding roles.assign, so no revoke leaves an organization with nobody who can grant roles. The id must belong to slug's organization; one that belongs to another is answered as 404, exactly like an id that does not exist. - List a user's ended sessions (admin)GET
/v1/admin/orgs/{slug}/users/{id}/session-historyReturns one page of the sessions of the user in the path that ended within the window, newest end first unless sort says otherwise, using opaque cursor (keyset) pagination. A user's active sessions are adminListSessions with user_id. - End every session of a user (admin)DEL
/v1/admin/orgs/{slug}/users/{id}/sessionsSigns the user out everywhere: ends each of their sessions, retires every refresh token they were issued until now (device-flow grants and grants that outlived their session included), withdraws any sign-in half-way through its second factor, and tells every relying party that took part in an ended session over the back channel. Each session is kept in the session history as ended by an administrator. A user with no session is answered 204 as well. - List an organization's active sessions (admin)GET
/v1/admin/orgs/{slug}/sessionsReturns one page of the sign-in sessions that are active in slug's organization, using opaque cursor (keyset) pagination. Bound the page size with limit and choose an ordering with sort (see x-sort-fields for what this endpoint accepts; the session id is appended so the ordering is total). Then walk the listing by passing the previous response's page.next_cursor back as cursor for as long as page.has_more is true; page.prev_cursor steps back the same way. Defaults to newest sign-in first. - End one session (admin)DEL
/v1/admin/orgs/{slug}/sessions/{sid}Ends the active session whose public id is sid: the user is signed out of it, the refresh tokens it issued are retired, and every relying party that took part in it is told over the back channel (OpenID Connect Back-Channel Logout 1.0). The session's other relying parties and the user's other sessions are not touched. It is kept in the session history as ended by an administrator. - List audit events (admin)GET
/v1/admin/orgs/{slug}/audit-eventsReturns one page of audit records for the organization, newest first, using opaque cursor (keyset) pagination. - Follow the audit log (admin)GET
/v1/admin/orgs/{slug}/audit-events/tailReturns the organization's audit records in the order they reached the store, from where the last read left off: the read a SIEM or a detector polls to follow the log as it grows. - Count audit events over time (admin)GET
/v1/admin/orgs/{slug}/audit-events/countsReturns how many audit records match, per time bucket and optionally per value of one column, as a dense, zero-filled UTC series. It takes exactly the audit list's filters, so the counts are the records the list pages through for the same parameters — except that reads of the audit log itself are left out unless include_audit_reads is set, so a dashboard's own reads do not dominate the chart drawn from them. - Rank the subjects behind audit events (admin)GET
/v1/admin/orgs/{slug}/audit-events/topReturns the subjects behind the audit records the filters match, by how many each caused: the principals (by=actor), the objects acted on (by=target, the accounts a run of refused sign-ins resolved to), the clients (by=client, resolved or only named, as the client_id filter matches them) or the addresses (by=client_ip). It takes the audit list's filters, so a ranking names exactly the records the list pages through for the same parameters, and reads of the audit log itself are left out unless include_audit_reads is set. - Get an audit event (admin)GET
/v1/admin/orgs/{slug}/audit-events/{id}Returns one audit record by id, subject to the same tenancy rules as the listing: a record belonging to another organization reads as missing, so a caller cannot use this to probe for one. - Get the audit event catalog (admin)GET
/v1/admin/audit-catalogReturns every audit event type this server can emit, with its category, default severity, verbosity level, whether configuration can suppress it, its declared metadata keys, and its translation key. - Get the threat overview (admin)GET
/v1/admin/orgs/{slug}/threatsReturns every signal of the threat catalog counted over the window: the failed sign-ins, locks and throttles that show credentials being guessed, the second-factor failures and locks, the grants and tokens refused at the protocol endpoints, the clients that failed to prove who they are, the registrations and names that look built to mislead, the privileged calls refused, and the malformed traffic turned away at the edge. Each signal carries its count, the count of the equal window before, its counts per bucket, the status that judges them against the signal's recommended threshold, the audit list filters that list exactly the records it counted, and the frameworks that describe the threat. Beside them, the shape of the window's failed sign-ins — how many, from how many addresses, against how many accounts — says whether one account is being hammered, many are being sprayed from one address, or a leaked list is being tried from many. - Get how the client address is determined (admin)GET
/v1/admin/deployment/client-ipReturns where this deployment reads the client address from (security.client_ip), the proxies it trusts and which of those are wider than they need to be, the trusted proxies that forwarded recent requests, and, when recent traffic looks like it arrives through a reverse proxy the configuration does not name, what was seen and the values that would read the client instead.