TypeScript server client
A typed TypeScript client wraps project users, organization invitations, and authorization reads.
examples/customer-app/src/server-client.ts
Developer docs
A practical integration guide for hosted auth, project-scoped APIs, locale negotiation, webhooks, and security defaults.
Quickstart
Start with a project, configure redirect boundaries, then choose hosted pages or direct API calls.
Endpoint map
These are the core hosted auth and verification endpoints exposed by the provider surface.
| Method | Path | Description |
|---|---|---|
| GET | /v1/auth/{project}/human-check/challenge | Create a short-lived first-party arithmetic human-verification challenge. |
| POST | /v1/auth/{project}/human-check/verify | Verify a human-verification answer and receive a short-lived one-time token. |
| POST | /v1/auth/{project}/queue/join | Join the optional self-hosted hosted-auth waiting room and receive an HttpOnly queue cookie. Registered return URIs are validated by Auth. |
| GET | /v1/auth/{project}/queue/status | Read the current self-hosted waiting-room position or admission state, including a validated return URI when supplied. |
| POST | /v1/auth/{project}/register | Create a project-scoped user and queue verification. |
| POST | /v1/auth/{project}/verify-email | Confirm an email verification token after validating the backing project and managed user; missing project or user fails as an invalid token before token consumption. |
| POST | /v1/auth/{project}/login | Create a session for an existing project user, or return MFA/attack-protection challenge state before session creation. |
| POST | /v1/auth/{project}/mfa/challenge/verify | Verify a login MFA challenge and then create the session. |
| POST | /v1/auth/{project}/mfa/totp/enroll | Enroll a TOTP factor for the current managed user. |
| POST | /v1/auth/{project}/mfa/totp/verify | Verify and activate a pending TOTP factor. |
| GET | /v1/auth/{project}/mfa/totp/factors | List current-user TOTP factors without returning secrets. |
| DELETE | /v1/auth/{project}/mfa/totp/factors/{factor} | Remove a current-user TOTP factor using the hosted session. |
| POST | /v1/auth/{project}/mfa/sms/enroll | Enroll an SMS MFA factor and return only safe phone preview metadata. |
| POST | /v1/auth/{project}/mfa/sms/challenge | Create an SMS one-time-code challenge without returning code material. |
| POST | /v1/auth/{project}/mfa/recovery-codes/regenerate | Regenerate one-time MFA recovery codes and return them only once. |
| POST | /v1/auth/{project}/refresh | Rotate the refresh token and renew the active session. |
| POST | /v1/auth/{project}/logout | End the current cookie-backed session. |
| POST | /v1/auth/{project}/magic-link/request | Queue a one-time sign-in link; token consumption fails closed if the backing project or managed user no longer resolves. |
| POST | /v1/auth/{project}/password-reset/request | Queue the password reset flow. |
| POST | /v1/auth/{project}/password-reset/confirm | Confirm a project-bound reset token, fail closed when the backing project or managed user is unavailable, set the replacement password, and revoke active sessions. |
| GET | /v1/auth/{project}/session | Read the current hosted-auth session state. |
| POST | /v1/auth/{project}/passkeys/login/start | Create a discoverable passkey login challenge for an allowed origin. |
| POST | /v1/auth/{project}/passkeys/login/finish | Verify a WebAuthn assertion and issue hosted-auth session cookies. |
| POST | /v1/auth/{project}/passkeys/register/start | Create a passkey enrollment challenge for the current managed user. |
| POST | /v1/auth/{project}/passkeys/register/finish | Verify and store the passkey credential for the current managed user. |
| GET | /v1/auth/{project}/passkeys | List active passkeys for the current managed user without returning credential secrets. |
| DELETE | /v1/auth/{project}/passkeys/{credential} | Remove one current-user passkey while preserving at least one usable sign-in method. |
| POST | /v1/auth/{project}/session-token | Exchange the current HttpOnly hosted-auth session for a 15-minute user access token with optional active managed-organization claims. |
| GET | /v1/oauth/{project}/.well-known/openid-configuration | Read project OpenID metadata for issuer, JWKS, userinfo, scopes, and claims. |
| POST | /v1/oauth/{project}/token | Exchange machine client credentials for a short-lived machine_access_token JWT. |
| GET | /v1/oauth/{project}/userinfo | Read the current authenticated user profile. |
| GET | /v1/oauth/{project}/jwks | Read public signing keys for token verification. |
| POST | /v1/oauth/{project}/introspect | Validate a managed-user access token from a trusted server with tokens:introspect scope. |
| POST | /v1/oauth/{project}/revoke | Revoke the hosted-auth session behind a managed-user access token from a trusted server with tokens:revoke scope. |
| GET | /v1/auth/{project}/me | Read the current managed user profile from the hosted-auth session. |
| PATCH | /v1/auth/{project}/me | Update the current managed user name or metadata without a management API key. |
| DELETE | /v1/auth/{project}/me | Deactivate the current managed user and revoke every current-user session. |
| POST | /v1/auth/{project}/me/password | Change the current managed user password with current-password proof and revoke other sessions. |
| POST | /v1/auth/{project}/me/email-change/request | Request a verified email change with current-password proof. |
| POST | /v1/auth/{project}/me/email-change/confirm | Confirm a verified email change and revoke other current-user sessions. |
| GET | /v1/auth/{project}/social-oauth/identities | List linked Social OAuth identities for the current managed user without returning provider subjects or token material. |
| DELETE | /v1/auth/{project}/social-oauth/identities/{identity} | Disconnect one current-user Social OAuth identity while preserving at least one usable sign-in method. |
| GET | /v1/auth/{project}/sso/identities | List linked Enterprise SSO identities for the current managed user without returning provider subjects, assertions, or token material. |
| DELETE | /v1/auth/{project}/sso/identities/{identity} | Disconnect one current-user Enterprise SSO identity while preserving at least one usable sign-in method. |
| GET | /v1/auth/{project}/sessions | List active sessions for the current managed user without returning token material. |
| GET | /v1/auth/{project}/sessions/{session} | Read one active current-user session with exact session scope and a redacted response. |
| POST | /v1/auth/{project}/sessions/revoke-others | Revoke every active current-user session except the caller session. |
| POST | /v1/auth/{project}/sessions/revoke-all | Revoke every active current-user session and expire hosted-auth cookies. |
| DELETE | /v1/auth/{project}/sessions/{session} | Revoke one current-user session; revoking the active session expires hosted-auth cookies. |
| POST | /v1/platform/auth/profile/email-change/request | Request a verified platform-account email change with current-password proof. |
| POST | /v1/platform/auth/profile/email-change/confirm | Confirm a verified platform-account email change and revoke sibling platform sessions. |
| GET | /v1/auth/{project}/authorization | List the current managed user roles and effective permissions. |
| POST | /v1/auth/{project}/authorization/check | Check whether the current managed user has a permission. |
| POST | /v1/auth/{project}/authorization/resource-check | Check whether the current managed user can act on a resource. |
| POST | /v1/auth/{project}/authorization/challenge | Issue a short-lived signed proof for an allowed permission. |
| POST | /v1/auth/{project}/authorization/challenge/verify | Verify a signed proof against the current hosted session and live permission. |
| POST | /v1/auth/{project}/social-oauth/start | Create a state-bound social OAuth authorization URL for an active provider. |
| POST | /v1/auth/{project}/social-oauth/callback | Exchange a social OAuth code server-side and issue hosted-auth session cookies. |
| POST | /v1/auth/{project}/social-oauth/apple/form-post-callback | Accept Apple form_post provider fields, consume one-time state, set session cookies, and redirect to the stored return URI without exposing tokens in the URL. |
| POST | /v1/auth/{project}/sso/discover | Find an active enterprise SSO connection for a work email domain without exposing secrets. |
| POST | /v1/auth/{project}/sso/start | Create a state-bound enterprise SSO authorization URL. |
| POST | /v1/auth/{project}/sso/callback | Consume SSO state. OIDC and signed SAML callbacks link or JIT provision a verified user and issue session cookies. |
| GET | /v1/auth/{project}/managed-organizations/memberships | List the current managed user managed-organization memberships from the hosted-auth session. |
| POST | /v1/auth/{project}/managed-organizations/memberships/{membership}/accept | Accept the current managed user pending verified-domain invitation without a management API key. |
| POST | /v1/auth/{project}/managed-organizations/memberships/{membership}/decline | Decline the current managed user pending membership without deleting audit history. |
| GET | /v1/auth/domains/resolve?domain=login.example.com | Resolve a verified custom domain to safe hosted-auth project routing metadata. |
| GET | /v1/platform/auth/sessions | List active dashboard sessions for the current platform user without returning token material. |
| GET | /v1/platform/auth/sessions/{session} | Read one active current-platform-user session with exact session scope and a redacted response. |
| POST | /v1/platform/auth/sessions/revoke-others | Revoke every active platform session except the caller session. |
| POST | /v1/platform/auth/sessions/revoke-all | Revoke every active platform session for the current platform user and expire dashboard cookies. |
| DELETE | /v1/platform/auth/sessions/{session} | Revoke one current-platform-user session; revoking the active session expires dashboard cookies. |
| GET | /v1/platform/orgs | List organizations available to the signed-in platform operator. |
| GET | /v1/platform/orgs/{org}/portal-links | List open one-time Admin Portal links without token material. |
| POST | /v1/platform/orgs/{org}/portal-links | Create a five-minute one-time Admin Portal link for an organization admin. |
| DELETE | /v1/platform/orgs/{org}/portal-links/{link} | Revoke an open Admin Portal link by consuming it server-side. |
| GET | /v1/platform/portal-links/resolve | Resolve and consume a public Admin Portal token into safe setup metadata. |
| POST | /v1/platform/portal/logout | Revoke the Admin Portal session and clear session/XSRF cookies without sending token material. |
| PATCH | /v1/platform/orgs/{org}/portal/settings | Update organization settings from the resolved Admin Portal session cookie and XSRF-TOKEN. |
| GET | /v1/platform/orgs/{org}/portal/billing | Read payment-neutral plan, feature, and limit state from a billing-scoped Admin Portal session. |
| PATCH | /v1/platform/orgs/{org}/portal/billing | Update organization billing entitlements from a billing-scoped Admin Portal session. |
| GET | /v1/platform/orgs/{org}/portal/billing/entitlements/{feature} | Check one feature entitlement from a billing-scoped Admin Portal session. |
| GET | /v1/platform/projects/{project}/portal/domains | List project domains from the resolved domain_verification Admin Portal session without challenge material. |
| POST | /v1/platform/projects/{project}/portal/domains | Create a project domain from the portal session and return the raw TXT value once. |
| POST | /v1/platform/projects/{project}/portal/domains/{domain}/verify | Verify a project-domain TXT challenge from the portal session without returning challenge material. |
| POST | /v1/platform/projects/{project}/portal/domains/{domain}/retry | Rotate a pending or failed project-domain TXT challenge from the portal session and return the raw value once. |
| DELETE | /v1/platform/projects/{project}/portal/domains/{domain} | Delete a project domain from the portal session without platform-session credentials. |
| GET | /v1/platform/projects/{project}/portal/enterprise-connections | List enterprise SSO connections from the resolved enterprise_sso Admin Portal session without provider secrets. |
| POST | /v1/platform/projects/{project}/portal/enterprise-connections | Create a SAML or OIDC enterprise connection from the portal session. |
| PATCH | /v1/platform/projects/{project}/portal/enterprise-connections/{connection} | Update an enterprise SSO connection from the portal session without returning secrets. |
| POST | /v1/platform/projects/{project}/portal/enterprise-connections/{connection}/validate | Validate an enterprise SSO connection from the portal session with safe diagnostics only. |
| DELETE | /v1/platform/projects/{project}/portal/enterprise-connections/{connection} | Delete an enterprise SSO connection from the portal session without platform-session credentials. |
| GET | /v1/platform/projects/{project}/portal/scim-directories | List SCIM directories from the resolved directory_sync Admin Portal session without token hashes. |
| POST | /v1/platform/projects/{project}/portal/scim-directories | Create a SCIM directory from the portal session and return the bearer token once. |
| GET | /v1/platform/projects/{project}/portal/scim-directories/{directory}/users | List synced SCIM directory users from the portal session without raw payloads or token material. |
| GET | /v1/platform/projects/{project}/portal/scim-directories/{directory}/groups | List synced SCIM directory groups from the portal session without raw payloads or token material. |
| POST | /v1/platform/projects/{project}/portal/scim-directories/{directory}/rotate-token | Rotate a SCIM directory bearer token from the portal session and return the replacement once. |
| GET | /v1/platform/orgs/{org}/portal/members | List organization members from the resolved members Admin Portal session without invitation token material. |
| POST | /v1/platform/orgs/{org}/portal/members/invite | Invite an organization member from the portal session and return the invitation token once. |
| PATCH | /v1/platform/orgs/{org}/portal/members/{member} | Update an organization member role or status from the portal session. |
| DELETE | /v1/platform/orgs/{org}/portal/members/{member} | Remove an organization member from the portal session without platform-session credentials. |
| GET | /v1/platform/orgs/{org}/portal/audit-logs | List audit logs from the resolved audit_exports Admin Portal session within retention. |
| GET | /v1/platform/orgs/{org}/portal/audit-logs/export | Export portal-scoped audit logs as CSV or JSON with no-store download headers. |
| GET | /v1/platform/projects/{project}/portal/webhooks | List webhook log stream endpoints from the resolved log_streams Admin Portal session. |
| POST | /v1/platform/projects/{project}/portal/webhooks | Create a webhook log stream endpoint and return the signing secret once. |
| PATCH | /v1/platform/projects/{project}/portal/webhooks/{webhook} | Update a webhook log stream endpoint without returning secret material. |
| POST | /v1/platform/projects/{project}/portal/webhooks/{webhook}/rotate-secret | Rotate a webhook log stream signing secret and return the replacement once. |
| GET | /v1/platform/projects/{project}/portal/webhooks/{webhook}/deliveries | List webhook delivery attempts from the portal session. |
| POST | /v1/platform/projects/{project}/portal/webhooks/{webhook}/deliveries/{delivery}/retry | Retry a webhook delivery from the portal session. |
| GET | /v1/platform/projects/{project}/portal/events | List recent project events visible to the portal log stream session. |
| GET | /v1/platform/projects/{project}/portal/certificate-renewal | Review certificate renewal readiness from the resolved certificate_renewal Admin Portal session without private keys. |
| GET | /v1/platform/orgs/{org}/billing | Read organization plan, subscription status, feature gates, and usage limits. |
| PATCH | /v1/platform/orgs/{org}/billing | Update payment-neutral organization entitlement state under owner/admin scope. |
| GET | /v1/platform/orgs/{org}/billing/entitlements/{feature} | Check one organization feature entitlement without exposing payment metadata. |
| GET | /v1/platform/projects/{project}/feature-flags | List project feature flags without token or credential material. |
| POST | /v1/platform/projects/{project}/feature-flags | Create a project feature flag with rollout and explicit targets. |
| PATCH | /v1/platform/projects/{project}/feature-flags/{flag} | Patch one project feature flag without returning targeting secrets. |
| DELETE | /v1/platform/projects/{project}/feature-flags/{flag} | Delete one project feature flag under manager scope. |
| GET | /v1/platform/orgs/{org}/domains | List organization domains without TXT values or verification hashes. |
| POST | /v1/platform/orgs/{org}/domains | Create an organization DNS challenge and return the raw TXT value once. |
| GET | /v1/platform/orgs/{org}/domains/{domain} | Read one organization domain without TXT values or verification hashes. |
| PATCH | /v1/platform/orgs/{org}/domains/{domain}/policy | Update verified-domain enrollment mode for onboarding decisions. |
| POST | /v1/platform/orgs/{org}/domains/enrollment/check | Check an email against verified organization-domain enrollment policy. |
| POST | /v1/platform/orgs/{org}/domains/{domain}/verify | Verify an organization domain after DNS TXT propagation without returning challenge material. |
| POST | /v1/platform/orgs/{org}/domains/{domain}/retry | Rotate a failed or pending organization-domain TXT challenge and return the new raw value once. |
| DELETE | /v1/platform/orgs/{org}/domains/{domain} | Delete an organization domain policy entry under owner/admin scope. |
| POST | /v1/platform/orgs/{org}/members/invite | Invite an organization member and return the raw one-time token once. |
| POST | /v1/platform/invitations/accept | Accept a pending organization invitation for the signed-in platform user. |
| GET | /v1/platform/projects | List tenant projects and their auth policy boundaries. |
| PATCH | /v1/platform/projects/{project} | Update project sign-up email-domain allow and block lists under owner/admin scope. |
| GET | /v1/platform/projects/{project}/domains | List project hosted-auth domains without TXT values or verification hashes. |
| POST | /v1/platform/projects/{project}/domains | Create a project DNS challenge and return the raw TXT value once. |
| GET | /v1/platform/projects/{project}/domains/{domain} | Read one project domain without TXT values or verification hashes. |
| POST | /v1/platform/projects/{project}/domains/{domain}/retry | Rotate a failed or pending project-domain TXT challenge and return the new raw value once. |
| POST | /v1/platform/projects/{project}/domains/{domain}/verify | Verify a project domain after DNS TXT propagation; mismatches move to failed without challenge material. |
| DELETE | /v1/platform/projects/{project}/domains/{domain} | Delete a project hosted-auth domain so it stops resolving. |
| GET | /v1/platform/projects/{project}/certificate-renewal | Review project certificate renewal readiness without private keys, certificate PEM, TXT values, or verification hashes. |
| GET | /v1/platform/projects/{project}/users | List project users visible to the organization manager. |
| POST | /v1/platform/projects/{project}/users | Create a project user under organization manager scope without returning password or token material. |
| PATCH | /v1/platform/projects/{project}/users/{user} | Patch a project user profile or metadata under organization manager scope. |
| POST | /v1/platform/projects/{project}/users/{user}/password-reset | Request an encrypted one-time password reset delivery for one managed user under platform-actor audit. |
| POST | /v1/platform/projects/{project}/users/{user}/deactivate | Deactivate a project user and revoke active sessions under platform-actor audit. |
| POST | /v1/platform/projects/{project}/users/{user}/reactivate | Reactivate a project user without creating a session. |
| POST | /v1/platform/projects/{project}/users/{user}/ban | Ban a project user and revoke active sessions without deleting account history. |
| POST | /v1/platform/projects/{project}/users/{user}/unban | Unban a project user without creating a session. |
| DELETE | /v1/platform/projects/{project}/users/{user} | Delete a project user after revoking active sessions; dependent credentials and sessions cascade server-side. |
| POST | /v1/platform/projects/{project}/users/{user}/impersonate | Create a 60-minute managed-user session for support impersonation with required reason capture. |
| GET | /v1/platform/projects/{project}/users/{user}/sessions | List active sessions for a managed user without returning token material. |
| GET | /v1/platform/projects/{project}/users/{user}/sessions/{session} | Read one active managed-user session using exact organization, project, user, and session scope without returning token material. |
| DELETE | /v1/platform/projects/{project}/users/{user}/sessions/{session} | Revoke one active managed-user session using exact organization, project, user, and session scope. |
| POST | /v1/platform/projects/{project}/users/{user}/sessions/revoke-all | Revoke every active session for one managed user and return only a bounded count. |
| GET | /v1/platform/projects/{project}/users/{user}/passkeys | List active passkeys for a managed user without returning credential hashes or encrypted WebAuthn material. |
| DELETE | /v1/platform/projects/{project}/users/{user}/passkeys/{credential} | Soft-remove one managed-user passkey using exact organization, project, user, and credential scope. |
| GET | /v1/platform/projects/{project}/managed-organizations | List project-scoped managed organizations for customer-application B2B access. |
| POST | /v1/platform/projects/{project}/managed-organizations | Create a managed organization without reusing provider dashboard organizations. |
| GET | /v1/platform/projects/{project}/managed-organizations/{managedOrg} | Read one managed organization under the same project and manager scope. |
| PATCH | /v1/platform/projects/{project}/managed-organizations/{managedOrg} | Patch or deactivate a managed organization under organization manager scope. |
| DELETE | /v1/platform/projects/{project}/managed-organizations/{managedOrg} | Deactivate a managed organization without deleting audit or membership history. |
| GET | /v1/platform/projects/{project}/managed-organizations/{managedOrg}/domain-links | List verified domain links that route onboarding into a managed organization. |
| POST | /v1/platform/projects/{project}/managed-organizations/{managedOrg}/domain-links | Link a verified organization domain to create only pending managed-organization onboarding memberships. |
| DELETE | /v1/platform/projects/{project}/managed-organizations/{managedOrg}/domain-links/{link} | Remove a verified domain link while preserving audit history. |
| GET | /v1/platform/projects/{project}/managed-organizations/{managedOrg}/memberships | List managed-user memberships for one project-scoped managed organization. |
| POST | /v1/platform/projects/{project}/managed-organizations/{managedOrg}/memberships | Add a same-project managed user to a managed organization with a bounded role and status. |
| PATCH | /v1/platform/projects/{project}/managed-organizations/{managedOrg}/memberships/{membership} | Patch a managed-organization membership role or lifecycle status. |
| DELETE | /v1/platform/projects/{project}/managed-organizations/{managedOrg}/memberships/{membership} | Remove a managed user from a managed organization without returning token material. |
| GET | /v1/platform/projects/{project}/enterprise-connections | List configured SAML/OIDC enterprise identity connections. |
| POST | /v1/platform/projects/{project}/enterprise-connections | Create a SAML or OIDC enterprise connection for a project. |
| POST | /v1/platform/projects/{project}/enterprise-connections/saml/metadata/preview | Fetch and validate a public HTTPS SAML metadata URL with safe diagnostics only. |
| GET | /v1/platform/projects/{project}/enterprise-connections/{connection}/saml/sp-metadata | Return safe SAML Service Provider entity ID, ACS URL, metadata URL, and metadata XML for IdP setup. |
| GET | /v1/platform/projects/{project}/social-oauth-providers | List configured social OAuth providers without exposing client secrets. |
| POST | /v1/platform/projects/{project}/social-oauth-providers | Create an Apple, Google, Microsoft, or GitHub OAuth provider for a project without returning the client secret. |
| GET | /v1/platform/projects/{project}/machine-clients | List project machine clients without exposing secrets or hashes. |
| POST | /v1/platform/projects/{project}/machine-clients | Create a machine client and return its raw secret once. |
| POST | /v1/platform/projects/{project}/machine-clients/{client}/rotate-secret | Rotate a machine client secret and return the replacement once. |
| DELETE | /v1/platform/projects/{project}/machine-clients/{client} | Revoke a machine client so new token exchanges fail. |
| GET | /v1/platform/projects/{project}/vault/objects | List Vault objects with redacted metadata only. |
| POST | /v1/platform/projects/{project}/vault/objects | Create a Vault object and store the secret encrypted at rest. |
| GET | /v1/platform/projects/{project}/vault/objects/{object} | Read Vault object metadata without returning the raw secret. |
| PATCH | /v1/platform/projects/{project}/vault/objects/{object} | Update Vault object metadata and optionally rotate the secret. |
| DELETE | /v1/platform/projects/{project}/vault/objects/{object} | Delete a Vault object without exposing secret material. |
| GET | /v1/platform/projects/{project}/vault/objects/{object}/secret | Reveal the raw Vault secret. This is the only Vault endpoint that returns raw secret material. |
| POST | /v1/platform/projects/{project}/authorization/resources | Create or update an authorization resource with an optional same-project parent. |
| POST | /v1/platform/projects/{project}/authorization/resource-role-assignments | Assign a project role to a managed user for one resource. |
| GET | /v1/platform/projects/{project}/users/{user}/authorization/resources | List resources where a managed user has one inherited resource permission. |
| GET | /v1/platform/projects/{project}/authorization/resource-users | List managed users that have one inherited permission on a resource. |
| GET | /v1/platform/projects/{project}/scim-directories | List SCIM directories without bearer tokens or token hashes. |
| POST | /v1/platform/projects/{project}/scim-directories | Create a SCIM directory and return its bearer token once. |
| GET | /v1/platform/projects/{project}/scim-directories/{directory}/users | List synced SCIM directory users without raw SCIM payloads or token material. |
| GET | /v1/platform/projects/{project}/scim-directories/{directory}/groups | List synced SCIM directory groups without raw SCIM payloads or token material. |
| POST | /v1/platform/projects/{project}/scim-directories/{directory}/rotate-token | Rotate a SCIM directory bearer token and return the replacement once. |
| GET | /v1/scim/{directory}/Users | List SCIM users for a directory using a bearer token. |
| POST | /v1/scim/{directory}/Users | Provision a managed user from a SCIM User payload. |
| PATCH | /v1/scim/{directory}/Users/{user} | Patch SCIM user lifecycle fields such as active. |
| GET | /v1/scim/{directory}/Groups | List SCIM groups and their members for a directory. |
| POST | /v1/scim/{directory}/Groups | Provision a SCIM group with members and mapped project roles. |
| PATCH | /v1/scim/{directory}/Groups/{group} | Patch SCIM group membership or role mappings. |
| POST | /v1/platform/projects/{project}/api-keys | Issue scoped server keys for project integrations. |
| POST | /v1/platform/projects/{project}/webhooks | Register project webhook endpoints and subscribed event types. |
Integration guides
Use these guides as the contract map for provider-grade integrations and enterprise identity expansion.
SDKs should wrap locale negotiation, CSRF headers, cookie credentials, typed envelopes, and retry-safe webhook setup.
SSO/OIDC integrations should bind providers to projects, validate callback state, and preserve project-scoped redirect policy.
Social OAuth provider configs are project-scoped, limited to Apple, Google, Microsoft, and GitHub, encrypted at rest, and bound to exact redirect allowlist entries. Apple profiles are verified from signed ID tokens delivered through form_post.
Machine clients give backend services scoped project access through OAuth client credentials, one-time secrets, short token lifetimes, and JWKS verification.
Vault stores project-scoped secrets with redacted reads, explicit secret reveal, and versioned updates for trusted backend integrations.
SCIM provisioning maps to project users, group memberships, source-aware role assignments, and deactivation audit records.
TOTP enrollment stores encrypted secrets, SMS factors store encrypted phone numbers and hashed one-time challenges, recovery codes are consumed once, and sessions are created only after verification. Prefer passkeys or TOTP for higher-assurance accounts.
Passkeys use WebAuthn resident credentials, exact project origins, one-time encrypted challenges, encrypted credential storage, and the same HttpOnly hosted-session boundary as password login.
Organizations own projects, members, settings, security policy, audit scope, and dashboard access.
B2B onboarding uses pending organization memberships, one-time hashed invitation tokens, expiry checks, and email-bound acceptance under the platform session.
Managed-user lifecycle APIs let platform admins create, patch, deactivate, and reactivate project users with manager-scope checks, audit events, and session revocation on deactivation.
Support impersonation is limited to organization owners/admins, requires a bounded reason, expires after 60 minutes, and stores impersonator metadata on the session and audit record.
Session inventory and revocation give support and security teams a precise device-level response path while preserving project and organization boundaries.
Hosted account pages combine current-user profile, session, passkey, MFA, recovery-code, and organization-membership controls behind HttpOnly cookies and CSRF.
Admin Portal links are owner/admin generated, intent scoped, one-time, hash stored, and expire after five minutes. Resolving a link creates a short-lived HttpOnly portal session for allowed mutations without returning session token material.
Billing entitlements are organization-scoped plan, feature, and limit records. They can gate product behavior without storing payment methods, invoices, or processor secrets.
Project feature flags target managed users or managed organizations, evaluate during session-token exchange, and expose only enabled flag keys in claims.
Organization domains verify company-owned email domains for SSO profile checks, invitation policy, and domain-based onboarding while rejecting consumer mailbox providers.
Hosted registration can return organization_enrollment when a verified domain policy produces suggestion, automatic invitation, or membership request decisions; manual and unverified domains stay silent.
Managed organizations are project-scoped customer-application groups with same-project managed-user memberships, roles, statuses, audit entries, and webhook events.
Roles group project permissions, direct grants cover exceptions, checks return booleans, and challenges issue short-lived signed proofs.
Webhook delivery uses subscribed events, signed secrets, delivery status, retry windows, and audit visibility.
Error envelopes include a stable code, localized message, request ID, and details object for field-level validation.
SDK integration shape
Use the examples as SDK seeds for strongly typed, localized, cookie-aware, and server-key-safe integrations.
A typed TypeScript client wraps project users, organization invitations, and authorization reads.
examples/customer-app/src/server-client.ts
A standard-library Python client mirrors the server-side management API shape for backend services.
examples/customer-app/python/auth_provider_client.py
A standard-library Go client seed covers management requests, locale headers, and typed API errors.
examples/customer-app/go/client.go
Every server SDK seed verifies timestamped HMAC webhook signatures against the event id and exact payload.
examples/customer-app/README.md#webhook-signature-verification
Every server SDK receiver example verifies the raw body before JSON parsing, with replay-safe idempotency guidance.
examples/customer-app/README.md#webhook-receiver-examples
A standard-library PHP client seed covers management requests, locale headers, and typed API errors.
examples/customer-app/php/AuthProviderClient.php
A standard-library Ruby client seed covers management requests, locale headers, and typed API errors.
examples/customer-app/ruby/auth_provider_client.rb
A standard-library Java client seed covers management requests, locale headers, and typed API errors.
examples/customer-app/java/AuthProviderServerClient.java
A standard-library Rust client seed covers management requests, locale headers, and typed API errors.
examples/customer-app/rust/src/lib.rs
A Foundation-based Swift client seed covers management requests, locale headers, and typed API errors.
examples/customer-app/swift/Sources/AuthProviderServerClient/AuthProviderServerClient.swift
Management API keys belong in server-side secret stores. Browser integrations should stay on cookies and CSRF.
examples/customer-app/README.md
Examples
Credentialed browser requests include cookies, locale headers, and the double-submit CSRF token.
fetch('/v1/auth/proj_example/login', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'X-Locale': 'en',
'X-XSRF-TOKEN': csrfToken
},
body: JSON.stringify({
email: 'user@example.com',
password: 'correct horse battery staple',
device_name: 'web'
})
})
// Hosted credential endpoints accept request fields only from JSON bodies with unknown fields rejected.
// Query strings and form fields are never accepted for register, login, verify-email, reset, magic-link, or MFA challenge input.Use the managed-user session cookie to ask whether a permission is currently granted.
await fetch('/v1/auth/proj_example/authorization/check', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfToken
},
body: JSON.stringify({
permission_key: 'invoices:approve'
})
})Resource checks use the same hosted session boundary and accept permission plus resource identifiers only from strict JSON bodies.
await fetch('/v1/auth/proj_example/authorization/resource-check', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfToken
},
body: JSON.stringify({
permission_key: 'documents:edit',
resource_type: 'folder',
resource_external_id: 'folder_child'
})
})
// Authorization check bodies are strict JSON only with unknown fields rejected.
// Do not send management API keys, bearer tokens, query strings, or form fields.Read and update the current managed-user profile through the hosted session; password changes require current_password and new_password, enforce password_min_length, low-complexity, and no-reuse policy with PASSWORD_POLICY_VIOLATION details.reason, keep the active session alive, revoke other sessions, and reject unknown fields.
const profile = await fetch('/v1/auth/proj_example/me', {
credentials: 'include',
headers: {
'X-XSRF-TOKEN': csrfToken
}
})
await fetch('/v1/auth/proj_example/me', {
method: 'PATCH',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfToken
},
body: JSON.stringify({
name: 'Person Example',
metadata: { theme: 'dark' },
metadata_set: true
})
})
// Profile self-service uses the current managed-user session.
// Profile, password-change, and email-change mutations accept fields only from strict JSON bodies.
// The profile patch accepts only name, metadata, and metadata_set; unknown fields fail with INVALID_PROFILE_UPDATE.
// Public metadata must not use reserved role, permission, organization, session, token, API key, credential, secret, or password keys.
// Password changes must also satisfy password_min_length, low-complexity, and no-reuse policy.
// Policy failures return PASSWORD_POLICY_VIOLATION with details.reason set to password_min_length, password_low_complexity, or password_reused.
// Email, password, ids, sessions, and token material use separate flows.
// Do not send Authorization, Cookie, organization_id, managed_user_id, query strings, or form fields from this helper.Current-user account deactivation uses the hosted session cookie, accepts no body, deactivates the signed-in managed user, revokes every active current-user session, and expires hosted-auth cookies.
await fetch('/v1/auth/proj_example/me', {
method: 'DELETE',
credentials: 'include',
headers: {
'X-XSRF-TOKEN': csrfToken
}
})
// Account deactivation uses only the current managed-user session.
// It accepts no request body, marks the current managed user deactivated,
// revokes every active current-user session including this device,
// and expires hosted-auth cookies.Request and confirm verified email changes through the current hosted session without returning raw one-time tokens to browser code.
await fetch('/v1/auth/proj_example/me/email-change/request', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfToken
},
body: JSON.stringify({
new_email: 'new-person@example.com',
current_password: currentPassword
})
})
await fetch('/v1/auth/proj_example/me/email-change/confirm', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfToken
},
body: JSON.stringify({
token: emailChangeToken
})
})
// Email changes are verified before the address changes.
// Email-change request and confirmation fields are strict JSON body values only.
// The request response never returns raw token material; delivery uses encrypted outbox payloads.
// Confirmation keeps the caller session active and revokes other current-user sessions.Platform users can request and confirm verified dashboard-account email changes through the platform session. The request requires current-password proof, delivers raw one-time tokens only through encrypted outbox payloads, and confirmation revokes sibling platform sessions.
await fetch('/v1/platform/auth/profile/email-change/request', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfToken
},
body: JSON.stringify({
new_email: 'new-admin@example.com',
current_password: currentPassword
})
})
await fetch('/v1/platform/auth/profile/email-change/confirm', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfToken
},
body: JSON.stringify({
token: platformEmailChangeToken
})
})
// Platform email changes use only the current dashboard session.
// Raw tokens are never returned; delivery uses encrypted outbox payloads.
// Confirmation preserves this session and revokes sibling platform sessions.Managed users can list and disconnect only their own linked Social OAuth identities through the hosted session. Responses omit provider subjects and token material, and the last passwordless sign-in method cannot be removed.
const identities = await fetch('/v1/auth/proj_example/social-oauth/identities', {
credentials: 'include',
headers: {
'X-XSRF-TOKEN': csrfToken
}
})
await fetch(`/v1/auth/proj_example/social-oauth/identities/${identities.data[0].id}`, {
method: 'DELETE',
credentials: 'include',
headers: {
'X-XSRF-TOKEN': csrfToken
}
})
// Responses contain id, provider_id, provider, email, last_login_at, created_at, and updated_at.
// They do not expose provider subjects, provider tokens, token hashes, API keys, or bearer headers.
// Disconnect fails with LAST_SIGN_IN_METHOD when it would remove the final usable passwordless sign-in method.Managed users can list and disconnect only their own linked Enterprise SSO identities through the hosted session. Responses omit provider subjects, assertions, and token material, and the last passwordless sign-in method cannot be removed.
const identities = await fetch('/v1/auth/proj_example/sso/identities', {
credentials: 'include',
headers: {
'X-XSRF-TOKEN': csrfToken
}
})
await fetch(`/v1/auth/proj_example/sso/identities/${identities.data[0].id}`, {
method: 'DELETE',
credentials: 'include',
headers: {
'X-XSRF-TOKEN': csrfToken
}
})
// Responses contain id, enterprise_connection_id, provider_type, email, last_login_at, created_at, and updated_at.
// They do not expose provider subjects, SAML assertions, OIDC tokens, token hashes, API keys, or bearer headers.
// Disconnect fails with LAST_SIGN_IN_METHOD when it would remove the final usable passwordless sign-in method.Managed users can list and revoke only their own hosted-auth sessions with cookie-backed CSRF requests; other users sessions are hidden as not found. They can also inspect one exact active session through the same cookie boundary without tenant overrides or token material.
const sessions = await fetch('/v1/auth/proj_example/sessions', {
credentials: 'include',
headers: {
'X-XSRF-TOKEN': csrfToken
}
})
const session = await fetch(`/v1/auth/proj_example/sessions/${sessions.data[0].id}`, {
credentials: 'include',
headers: {
'X-XSRF-TOKEN': csrfToken
}
})
await fetch(`/v1/auth/proj_example/sessions/${sessions.data[0].id}`, {
method: 'DELETE',
credentials: 'include',
headers: {
'X-XSRF-TOKEN': csrfToken
}
})
await fetch('/v1/auth/proj_example/sessions/revoke-others', {
method: 'POST',
credentials: 'include',
headers: {
'X-XSRF-TOKEN': csrfToken
}
})
await fetch('/v1/auth/proj_example/sessions/revoke-all', {
method: 'POST',
credentials: 'include',
headers: {
'X-XSRF-TOKEN': csrfToken
}
})
// The revoke-all operation includes the caller session, expires hosted-auth cookies, and returns only an acknowledgement plus revoked session count.
// Session self-service uses only the current managed-user session.
// Refresh and logout use only HttpOnly hosted-auth cookies plus CSRF and do not accept session_id or refresh_token in request bodies.
// Session responses include created_at, updated_at, last_active_at, expires_at, revoked_at, and ended_at.
// The provider applies server-owned idle expiry from the stored last_active_at value and tenant session_idle_timeout_minutes; clients never send a client-supplied activity timestamp.
// It never accepts organization_id, managed_user_id, API keys, bearer tokens, refresh tokens, or user-selected request bodies.
// Other users sessions return RESOURCE_NOT_FOUND; revoking the current session also expires hosted-auth cookies.Platform users can list and revoke only their own dashboard sessions with cookie-backed CSRF requests; other platform users sessions are hidden as not found. They can also inspect one exact active dashboard session through the same cookie boundary without tenant overrides or token material.
const sessions = await fetch('/v1/platform/auth/sessions', {
credentials: 'include',
headers: {
'X-XSRF-TOKEN': csrfToken
}
})
const session = await fetch(`/v1/platform/auth/sessions/${sessions.data[0].id}`, {
credentials: 'include',
headers: {
'X-XSRF-TOKEN': csrfToken
}
})
await fetch(`/v1/platform/auth/sessions/${sessions.data[0].id}`, {
method: 'DELETE',
credentials: 'include',
headers: {
'X-XSRF-TOKEN': csrfToken
}
})
await fetch('/v1/platform/auth/sessions/revoke-others', {
method: 'POST',
credentials: 'include',
headers: {
'X-XSRF-TOKEN': csrfToken
}
})
await fetch('/v1/platform/auth/sessions/revoke-all', {
method: 'POST',
credentials: 'include',
headers: {
'X-XSRF-TOKEN': csrfToken
}
})
// Platform session self-service uses only the current platform session.
// Platform logout uses only the HttpOnly dashboard session cookie plus CSRF and does not accept session_id in request bodies.
// Session responses include created_at, updated_at, last_active_at, expires_at, revoked_at, and ended_at.
// The provider applies server-owned idle expiry from the stored last_active_at value and tenant session_idle_timeout_minutes where configured; clients never send a client-supplied activity timestamp.
// It never accepts organization_id, platform_user_id, API keys, bearer tokens, refresh tokens, or request bodies.
// Other platform users sessions return RESOURCE_NOT_FOUND; revoking the current session also expires dashboard cookies.Send signed-in managed users to the hosted account page for profile, sessions, passkeys, MFA, recovery codes, and organization memberships without browser token storage.
// Link signed-in managed users to the hosted account center.
// Explicit project route:
window.location.assign('/auth/{project}/account')
// Verified custom hosted-auth domain route:
window.location.assign('/auth/account')
// The account page uses the same HttpOnly hosted session cookie and CSRF boundary
// as these current-user APIs:
await fetch('/v1/auth/{project}/me', {
credentials: 'include',
headers: { 'X-XSRF-TOKEN': csrfToken }
})
await fetch('/v1/auth/{project}/mfa/recovery-codes/regenerate', {
method: 'POST',
credentials: 'include',
headers: { 'X-XSRF-TOKEN': csrfToken }
})
// Do not pass management API keys, bearer tokens, organization_id, or secret hashes from browser code.Challenge tokens are short-lived signed proofs for a single project, user, permission, and request. The managed-session verifier checks the token signature, request id, expiry, current user, and live permission before a privileged action continues.
const proof = await fetch('/v1/auth/proj_example/authorization/challenge', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfToken
},
body: JSON.stringify({
permission_key: 'invoices:approve'
})
})
const verified = await fetch('/v1/auth/proj_example/authorization/challenge/verify', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfToken
},
body: JSON.stringify({
token: proof.data.token,
permission_key: 'invoices:approve',
request_id: proof.data.request_id
})
})
// Challenge issue and verify calls accept proof fields only from JSON bodies with unknown fields rejected.
// The provider must have AUTH_AUTHZ_CHALLENGE_SECRET configured with at least 32 bytes.
// Missing or weak secrets fail closed with AUTHORIZATION_CHALLENGE_SECRET_REQUIRED or AUTHORIZATION_CHALLENGE_SECRET_WEAK.
// The verifier rechecks the current cookie session, proof signature, request id, expiry, and live permission.MFA challenge verification accepts a TOTP authenticator code before session cookies are issued, keeping step-up state server-side. The same code field can also carry a one-time recovery code. The backend consumes recovery codes once and never asks browser code for a separate recovery_code secret. SMS factors create hashed one-time-code challenges, return only a phone preview, and are best paired with TOTP or passkeys for stronger assurance.
const login = await fetch('/v1/auth/proj_example/login', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfToken
},
body: JSON.stringify({
email: 'user@example.com',
password: 'correct horse battery staple'
})
})
// SMS factors use the same challenge verifier after the server creates a delivery challenge.
await fetch('/v1/auth/proj_example/mfa/sms/challenge', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfToken
}
})
// If login.data.mfa_required is true, verify before any session cookie is issued.
await fetch('/v1/auth/proj_example/mfa/challenge/verify', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfToken
},
body: JSON.stringify({
managed_user_id: login.data.managed_user_id,
challenge_id: login.data.challenge_id,
code: '123456' // Or a one-time recovery code such as abcd-efgh-jklm-npqr.
})
})Enroll passkeys from an existing managed-user session. WebAuthn challenge state stays server-side, and the verified credential is stored encrypted at rest.
const start = await fetch('/v1/auth/proj_example/passkeys/register/start', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfToken
},
body: JSON.stringify({
origin: window.location.origin
})
})
const credential = await navigator.credentials.create({
publicKey: start.data.public_key
})
await fetch('/v1/auth/proj_example/passkeys/register/finish', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfToken
},
body: JSON.stringify({
challenge_id: start.data.challenge_id,
name: 'Work laptop',
...credential.toJSON()
})
})
// Passkey ceremony endpoints accept fields only from JSON bodies with unknown fields rejected.
// Query strings and form fields are never accepted for passkey ceremony input.Start a discoverable WebAuthn login, verify the assertion, then let the hosted-auth session cookie boundary carry the browser session.
const start = await fetch('/v1/auth/proj_example/passkeys/login/start', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfToken
},
body: JSON.stringify({
origin: window.location.origin
})
})
const assertion = await navigator.credentials.get({
publicKey: start.data.public_key
})
const login = await fetch('/v1/auth/proj_example/passkeys/login/finish', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfToken
},
body: JSON.stringify({
challenge_id: start.data.challenge_id,
device_name: 'Chrome on macOS',
...assertion.toJSON()
})
})
// login.data.verified === true
// HttpOnly session cookies are now set.
// Passkey ceremony endpoints accept fields only from JSON bodies with unknown fields rejected.
// Query strings and form fields are never accepted for passkey ceremony input.Project sign-up restrictions normalize allow and block lists server-side and enforce organization password_min_length plus low-complexity policy before hashing. Matching blocked domains, non-allowlisted domains, and PASSWORD_POLICY_VIOLATION with details.reason password_min_length or password_low_complexity fail before a managed user, password hash, or one-time token is stored. Password reset and current-password change also reject password_reused before token, hash, or session mutation. Attack protection adds server-side bot user-agent and disposable email decisions without returning CAPTCHA secrets.
await fetch('/v1/platform/projects/proj_example?organization_id=org_example', {
method: 'PATCH',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfToken
},
body: JSON.stringify({
organization_id: 'org_example',
email_domain_allowlist: ['example.com', 'trusted.example'],
email_domain_blocklist: ['disposable.example']
})
})
// Registration rejects EMAIL_DOMAIN_RESTRICTED and PASSWORD_POLICY_VIOLATION before creating a user or one-time token.
// Registration, password reset, and magic-link fields are strict JSON-body-only inputs with unknown fields rejected.
// Registration password policy failures include details.reason as password_min_length or password_low_complexity.
// Password reset and current-password change can also return password_reused before mutating tokens, hashes, or sessions.
// Reset tokens are project-bound; wrong-project, unavailable-project, or unavailable-user tokens fail before token consumption or session revocation.
// Successful password reset consumes the reset token and revokes active sessions without returning session ids.
// Responses never include CAPTCHA secrets, token hashes, or secret material.Attack protection evaluates configured bot user-agent, disposable email, subaddress, and IP signals on hosted registration and login, and applies bounded failed-login lockouts. Deny decisions return ATTACK_PROTECTION_BLOCKED before registration side effects; challenge decisions return ATTACK_PROTECTION_CHALLENGE_REQUIRED after valid login credentials and before session creation.
await fetch('/v1/platform/projects/proj_example?organization_id=org_example', {
method: 'PATCH',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfToken
},
body: JSON.stringify({
organization_id: 'org_example',
attack_protection: {
enabled: true,
bot_user_agent_mode: 'challenge',
disposable_email_mode: 'deny',
disposable_email_domains: ['mailinator.example'],
email_subaddress_mode: 'deny',
ip_restriction_mode: 'challenge',
ip_allowlist: ['203.0.113.10'],
ip_blocklist: ['198.51.100.0/24'],
failed_login_lockout_threshold: 7,
failed_login_lockout_duration_minutes: 45
}
})
})
// Register deny decisions return ATTACK_PROTECTION_BLOCKED before password hashing, user creation, or token creation.
// Login challenge decisions return ATTACK_PROTECTION_CHALLENGE_REQUIRED after valid credentials and before session creation.
// The 403 body includes details.challenge_kind only.
// Responses never include CAPTCHA secrets, risk API credentials, bearer material, or token hashes.Audit logs expose only safe attack-protection classifiers so operators can review monitor, challenge, and deny decisions without seeing risk-provider secrets or token material. The provider audit boundary sanitizes metadata before record, list, and export responses.
const auditLogs = await fetch('/v1/platform/audit-logs?project_id=proj_example', {
method: 'GET',
credentials: 'include',
headers: {
Accept: 'application/json'
}
})
// Attack-protection audit metadata uses safe classifiers only:
// metadata.attack_protection_action -> monitor, challenge, or deny
// metadata.attack_protection_signals -> bot_user_agent, disposable_email_domain, ip_restriction, email_subaddress
// metadata.challenge_kind -> managed_challenge when a login challenge is required
// Audit metadata is sanitized at the provider audit boundary before record, list, or export responses.
// Public correlation IDs such as token_id, session_id, and api_key_id remain available.
// Passwords, token hashes, raw tokens, client secrets, private keys, certificate PEM, TXT challenge values,
// SAML metadata XML, provider subjects, and payment identifiers are removed.Create SAML enterprise connections with normalized domains and a redirect URI that is already allowlisted on the project.
await fetch('/v1/platform/projects/proj_example/enterprise-connections?organization_id=org_example', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfToken
},
body: JSON.stringify({
name: 'Example Okta',
provider_type: 'saml',
domains: ['example.com'],
redirect_uri: 'https://app.example.com/sso/callback',
saml_metadata_xml: '<EntityDescriptor entityID="https://idp.example.com"></EntityDescriptor>'
})
})Preview a public HTTPS IdP metadata URL on the backend before saving SAML XML. The response returns safe diagnostics only and never returns raw metadata XML.
await fetch('/v1/platform/projects/proj_example/enterprise-connections/saml/metadata/preview?organization_id=org_example', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfToken
},
body: JSON.stringify({
metadata_url: 'https://idp.example.com/metadata.xml'
})
})
// Returns entity_id, content_type, bytes, checks, and errors.
// Raw metadata XML and secrets are never returned.Fetch Service Provider setup values for an active SAML connection. The response includes entity_id, acs_url, metadata_url, and SP metadata XML, but never returns IdP XML or provider secrets.
const setup = await fetch('/v1/platform/projects/proj_example/enterprise-connections/sso_example/saml/sp-metadata?organization_id=org_example', {
method: 'GET',
credentials: 'include',
headers: {
'X-XSRF-TOKEN': csrfToken
}
})
// setup.data.entity_id -> SP Entity ID
// setup.data.acs_url -> Assertion Consumer Service URL
// setup.data.metadata_xml -> safe SP metadata XML for IdP import
// IdP XML, OIDC secrets, token hashes, and API keys are never returned.OIDC client secrets are accepted on create or rotation but are stored encrypted and omitted from read responses.
await fetch('/v1/platform/projects/proj_example/enterprise-connections?organization_id=org_example', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfToken
},
body: JSON.stringify({
name: 'Example OIDC',
provider_type: 'oidc',
domains: ['example.com'],
redirect_uri: 'https://app.example.com/sso/callback',
oidc_issuer_url: 'https://idp.example.com',
oidc_client_id: 'client_id_from_idp',
oidc_client_secret: 'stored-encrypted-and-never-returned'
})
})Configure Apple, Google, Microsoft, or GitHub social sign-in for a project. Client secrets are encrypted at rest, omitted from read responses, and redirect URIs must exactly match the project allowlist.
await fetch('/v1/platform/projects/proj_example/social-oauth-providers?organization_id=org_example', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfToken
},
body: JSON.stringify({
provider: 'google',
client_id: 'google-client-id',
client_secret: 'stored-encrypted-and-never-returned',
redirect_uri: 'https://app.example.com/oauth/callback',
scopes: ['openid', 'email', 'profile']
})
})Start social OAuth with an active provider and allowlisted redirect URI. Google, Microsoft, and GitHub callbacks post code to the JSON callback endpoint. Apple uses form_post to a provider callback route that is one-time state-bound, sets HttpOnly cookies, and redirects only to the stored allowlisted return_uri without exposing provider tokens.
const start = await fetch('/v1/auth/proj_example/social-oauth/start', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfToken
},
body: JSON.stringify({
provider: 'google',
redirect_uri: 'https://app.example.com/oauth/callback',
return_uri: 'https://app.example.com/oauth/complete',
state: 'customer-return-state'
})
})
// Redirect to start.data.authorization_url. After Google, Microsoft, or GitHub returns, post state plus code.
const callback = await fetch('/v1/auth/proj_example/social-oauth/callback', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfToken
},
body: JSON.stringify({
provider: 'google',
state: start.data.state,
code: 'provider-authorization-code',
device_name: 'Chrome on macOS'
})
})
// callback.data.status === 'authenticated'
// HttpOnly session cookies are now set, and callback.data.session contains the hosted-auth session.
// Apple uses response_mode=form_post and posts code plus id_token directly to:
// POST /v1/auth/{project}/social-oauth/apple/form-post-callback
// Apple callback state, code, and id_token are accepted only from application/x-www-form-urlencoded form body fields.
// Non-Apple Social OAuth ceremony fields are strict JSON-body-only inputs with unknown fields rejected.
// Query strings and form fields are never accepted for non-Apple Social OAuth start or callback input.
// The provider POST route is rate-limited and state-bound but intentionally not CSRF-gated.
// It sets HttpOnly session cookies and redirects only to the stored allowlisted return_uri.
// Provider code, ID token, access token, and session identifiers are never placed in the redirect URL.Machine clients are project-scoped service identities. The raw secret is returned once and then stored only as a hash.
const client = await fetch('/v1/platform/projects/proj_example/machine-clients?organization_id=org_example', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfToken
},
body: JSON.stringify({
name: 'Billing worker',
scopes: ['events:write', 'webhooks:deliver']
})
})
// client.data.client_secret is shown once. Store it only in your service secret manager.Trusted backend services exchange client credentials for short-lived machine JWTs and verify them with the project JWKS before use.
const token = await fetch('/v1/oauth/proj_example/token', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
grant_type: 'client_credentials',
client_id: 'mcli_example',
client_secret: process.env.AUTH_PROVIDER_MACHINE_CLIENT_SECRET,
scope: 'events:write webhooks:deliver'
})
})
// token.data.token_type === 'Bearer'
// Verify the ES256 JWT from JWKS before trusting token.data.token_type === 'machine_access_token'.Create, read, update, delete, and reveal project Vault objects with explicit organization scope and redacted metadata.
const created = await fetch('/v1/platform/projects/proj_example/vault/objects?organization_id=org_example', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfToken
},
body: JSON.stringify({
key: 'database_password',
name: 'Database password',
description: 'Primary database secret',
metadata: { env: 'prod' },
secret: 'stored-encrypted-at-rest'
})
})
const revealed = await fetch('/v1/platform/projects/proj_example/vault/objects/vault_db/secret?organization_id=org_example', {
method: 'GET',
credentials: 'include'
})
// List/get/update/delete return redacted metadata only.
// The raw secret value is returned only by the explicit reveal endpoint.Discover the active enterprise connection for a work email before starting SSO. Discovery only selects the connection and redirect URI; the callback still verifies the signed or verified provider email against the connection domain.
const discovered = await fetch('/v1/auth/proj_example/sso/discover', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfToken
},
body: JSON.stringify({
email: 'person@example.com'
})
})
// Use discovered.data.connection_id and discovered.data.redirect_uri
// to start SSO. Discovery is not membership proof; callback still verifies
// the signed/verified provider email against the active connection domains.Start enterprise SSO with an active connection and allowlisted redirect URI. OIDC callbacks exchange the authorization code server-side, SAML callbacks validate a trusted signed assertion, and both link or JIT provision the verified user before issuing hosted-auth session cookies.
const start = await fetch('/v1/auth/proj_example/sso/start', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfToken
},
body: JSON.stringify({
connection_id: 'sso_example',
redirect_uri: 'https://app.example.com/sso/callback',
state: 'customer-return-state'
})
})
// Redirect to start.data.authorization_url. After the IdP returns, post state plus an OIDC code or SAMLResponse.
const callback = await fetch('/v1/auth/proj_example/sso/callback', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfToken
},
body: JSON.stringify({
connection_id: 'sso_example',
state: start.data.state,
code: 'provider-authorization-code',
device_name: 'Chrome on macOS'
})
})
// callback.data.status === 'authenticated'
// HttpOnly session cookies are now set, and callback.data.session contains the hosted-auth session.
// SSO ceremony fields are strict JSON-body-only inputs with unknown fields rejected.
// Query strings and form fields are never accepted for SSO discovery, start, or callback input.Create a project directory to receive a one-time SCIM bearer token. Only the token hash is stored after creation or rotation.
const directory = await fetch('/v1/platform/projects/proj_example/scim-directories?organization_id=org_example', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfToken
},
body: JSON.stringify({
name: 'Example Okta Directory',
provider: 'okta'
})
})
// directory.token is shown once. Store it in the IdP SCIM bearer-token field.SCIM Users endpoints are bearer-token authenticated and provision, update, or deactivate managed users for the directory project.
await fetch('/v1/scim/dir_example/Users', {
method: 'POST',
headers: {
// Send the SCIM directory token in the HTTP authorization header from your IdP or backend only.
'Content-Type': 'application/scim+json'
},
body: JSON.stringify({
schemas: ['urn:ietf:params:scim:schemas:core:2.0:User'],
externalId: '00u123',
userName: 'person@example.com',
displayName: 'Example Person',
active: true,
emails: [{ value: 'person@example.com', primary: true }]
})
})
// DELETE or PATCH active=false deactivates the managed user and revokes active sessions.
// POST /v1/platform/projects/{project}/users/{user}/lock revokes active sessions and sets a bounded lock duration.
// POST /v1/platform/projects/{project}/users/{user}/unlock clears failed_login_count and locked_until.
// DELETE /v1/platform/projects/{project}/users/{user} revokes active sessions before deleting the managed user.SCIM Groups endpoints synchronize group membership and optional project-role mappings without overwriting manual role assignments.
await fetch('/v1/scim/dir_example/Groups', {
method: 'POST',
headers: {
// Send the SCIM directory token in the HTTP authorization header from your IdP or backend only.
'Content-Type': 'application/scim+json'
},
body: JSON.stringify({
schemas: ['urn:ietf:params:scim:schemas:core:2.0:Group'],
externalId: '00g-admins',
displayName: 'Admins',
members: [{ value: 'dusr_example', display: 'person@example.com' }],
roles: [{ value: 'role_admin', type: 'project_role' }]
})
})
// Group memberships grant mapped project-role permissions without overwriting manual grants.Organization invitations return a raw token once, store only a hash, expire automatically, and can be accepted only by the signed-in platform user whose email matches the invite.
const invite = await fetch('/v1/platform/orgs/org_example/members/invite', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfToken
},
body: JSON.stringify({
email: 'admin@example.com',
role: 'admin'
})
})
// invite.data.invitation_token is shown once. Send it through your mail system.
await fetch('/v1/platform/invitations/accept', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfToken
},
body: JSON.stringify({
organization_id: 'org_example',
token: invite.data.invitation_token
})
})Platform owners/admins can create, patch, deactivate, and reactivate project users while preserving tenant scope, audit records, events, and session revocation rules.
const user = await fetch('/v1/platform/projects/proj_example/users?organization_id=org_example', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfToken
},
body: JSON.stringify({
email: 'person@example.com',
name: 'Example Person',
password: 'correct horse battery staple',
metadata: { plan: 'gold' }
})
})
await fetch(`/v1/platform/projects/proj_example/users/${user.data.id}?organization_id=org_example`, {
method: 'PATCH',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfToken
},
body: JSON.stringify({
name: 'Example Person',
metadata: { plan: 'enterprise' },
metadata_set: true
})
})
await fetch(`/v1/platform/projects/proj_example/users/${user.data.id}/deactivate?organization_id=org_example`, {
method: 'POST',
credentials: 'include',
headers: { 'X-XSRF-TOKEN': csrfToken }
})
// Deactivation revokes active sessions and records platform-actor audit entries.Platform owners/admins can request a reset delivery for a known managed user without returning raw reset tokens, hashes, API keys, or password material to browser code.
await fetch('/v1/platform/projects/proj_example/users/muser_example/password-reset?organization_id=org_example', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfToken
},
body: JSON.stringify({
redirect_uri: 'https://app.example.test/auth/reset-password'
})
})
// The dashboard response is only { data: { ok: true } }.
// Delivery workers receive an encrypted one-time reset token from the outbox.
// Do not render raw reset tokens, token hashes, API keys, bearer tokens, or password material in browser code.Admin/support impersonation creates a managed-user session through cookies, requires a reason, marks the session as impersonated, and records the platform actor in audit logs.
const session = await fetch('/v1/platform/projects/proj_example/users/muser_example/impersonate?organization_id=org_example', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfToken
},
body: JSON.stringify({
reason: 'Debug checkout failure reported in ticket 1842',
device_name: 'support console'
})
})
// session.data.impersonated === true
// The managed-user session expires after 60 minutes and stays inside HttpOnly cookies.Platform owners/admins can list active managed-user sessions, inspect one exact active session, revoke one exact session, or revoke all sessions without exposing refresh tokens or hashes.
const sessions = await fetch('/v1/platform/projects/proj_example/users/muser_example/sessions?organization_id=org_example', {
method: 'GET',
credentials: 'include'
})
const session = await fetch(`/v1/platform/projects/proj_example/users/muser_example/sessions/${sessions.data[0].id}?organization_id=org_example`, {
method: 'GET',
credentials: 'include'
})
await fetch(`/v1/platform/projects/proj_example/users/muser_example/sessions/${sessions.data[0].id}?organization_id=org_example`, {
method: 'DELETE',
credentials: 'include',
headers: {
'X-XSRF-TOKEN': csrfToken
}
})
await fetch('/v1/platform/projects/proj_example/users/muser_example/sessions/revoke-all?organization_id=org_example', {
method: 'POST',
credentials: 'include',
headers: {
'X-XSRF-TOKEN': csrfToken
}
})
// session.data contains redacted device, IP, user agent, lifecycle timestamps, expiry, and impersonation metadata.
// Managed-user session responses include created_at, updated_at, last_active_at, expires_at, revoked_at, and ended_at.
// Responses never include refresh tokens, token hashes, cookies, API keys, or bearer material.Platform owners/admins can list and remove a managed user passkey without exposing WebAuthn hashes, encrypted credentials, raw public keys, API keys, or bearer tokens.
const passkeys = await fetch('/v1/platform/projects/proj_example/users/muser_example/passkeys?organization_id=org_example', {
method: 'GET',
credentials: 'include'
})
await fetch(`/v1/platform/projects/proj_example/users/muser_example/passkeys/${passkeys.data.passkeys[0].id}?organization_id=org_example`, {
method: 'DELETE',
credentials: 'include',
headers: {
'X-XSRF-TOKEN': csrfToken
}
})
// Platform passkey inventory returns display metadata only: id, name, transports, backup flags, last_used_at, and created_at.
// Credential hashes, encrypted WebAuthn blobs, raw public keys, API keys, and bearer tokens are never exposed to browser code.Audit exports require an organization or project scope, reuse the platform session, apply the organization retention window, and return CSV or JSON with Content-Disposition, Cache-Control: no-store, and Pragma: no-cache. Audit metadata is sanitized by the provider audit boundary before record, list, and export responses; public IDs remain while credentials, tokens, hashes, keys, certificates, provider subjects, and payment identifiers are removed.
const csv = await fetch('/v1/platform/audit-logs/export?organization_id=org_example&format=csv&limit=1000', {
method: 'GET',
credentials: 'include',
headers: {
Accept: 'text/csv'
}
})
// Exports require platform-session scope, apply organization retention, and return
// Content-Disposition, Cache-Control: no-store, and Pragma: no-cache download headers.
// Audit metadata is sanitized before export; public IDs remain, credential material is removed.Billing entitlement state stores plan, subscription status, feature gates, and numeric limits only. Payment processor sync and card handling stay outside this API.
await fetch('/v1/platform/orgs/org_example/billing', {
method: 'PATCH',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfToken
},
body: JSON.stringify({
plan_key: 'scale',
subscription_status: 'active',
features: {
enterprise_sso: true,
audit_exports: true
},
limits: {
managed_users: 2500,
webhooks: 25
}
})
})
const entitlement = await fetch('/v1/platform/orgs/org_example/billing/entitlements/enterprise_sso', {
method: 'GET',
credentials: 'include'
})
// entitlement.data.enabled gates product behavior. Responses never include card or processor secrets.Project feature flags use platform-session management APIs, evaluate against the active managed-user session, and add only normalized enabled keys to session-token claims.
await fetch('/v1/platform/projects/proj_example/feature-flags?organization_id=org_example', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfToken
},
body: JSON.stringify({
key: 'beta_dashboard',
name: 'Beta dashboard',
description: 'Preview the new dashboard',
enabled: true,
rollout_percentage: 100,
managed_organization_ids: ['morg_acme'],
user_ids: []
})
})
const token = await fetch('/v1/auth/proj_example/session-token?managed_organization_id=morg_acme', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfToken
}
})
// token.data.feature_flags contains enabled keys such as beta_dashboard.
// managed_organization_id is query-only and is not accepted from JSON or form bodies.
// Targeting rules stay server-side and are never returned in the access-token response.Custom session claim templates map approved user, organization, role, permission, and feature-flag sources into bounded custom_claims.
await fetch('/v1/platform/projects/proj_example?organization_id=org_example', {
method: 'PATCH',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfToken
},
body: JSON.stringify({
custom_session_claims: [
{ key: 'plan', source: 'user.metadata.plan' },
{ key: 'flags', source: 'feature_flags' }
]
})
})
const token = await fetch('/v1/auth/proj_example/session-token', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfToken
}
})
// token.data.custom_claims contains only configured safe values.
// Reserved JWT claims and sensitive metadata sources are rejected.Project domains prove hosted-auth hostname ownership with DNS and fail closed when verification fails, the domain is deleted, or hosted auth is disabled.
const created = await fetch('/v1/platform/projects/proj_example/domains?organization_id=org_example', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfToken
},
body: JSON.stringify({
domain: 'login.example.com'
})
})
// created.data.txt_record_value starts with auth-provider-domain-verification and is shown once.
const detail = await fetch('/v1/platform/projects/proj_example/domains/pdom_example?organization_id=org_example', {
method: 'GET',
credentials: 'include'
})
if (detail.data?.status === 'failed') {
await fetch('/v1/platform/projects/proj_example/domains/pdom_example/retry?organization_id=org_example', {
method: 'POST',
credentials: 'include',
headers: {
'X-XSRF-TOKEN': csrfToken
}
})
}
await fetch('/v1/platform/projects/proj_example/domains/pdom_example/verify?organization_id=org_example', {
method: 'POST',
credentials: 'include',
headers: {
'X-XSRF-TOKEN': csrfToken
}
})
await fetch('/v1/platform/projects/proj_example/domains/pdom_example?organization_id=org_example', {
method: 'DELETE',
credentials: 'include',
headers: {
'X-XSRF-TOKEN': csrfToken
}
})
// failed domains can retry with a rotated TXT value; verified retry is a redacted no-op.
// deleted domains stop resolving for hosted-auth routing and never expose verification hashes.Organization domains prove company ownership with DNS, then drive manual, suggestion, automatic invitation, and membership request enrollment modes.
const created = await fetch('/v1/platform/orgs/org_example/domains', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfToken
},
body: JSON.stringify({
domain: 'example.com'
})
})
// created.data.txt_record_name points to DNS.
// created.data.txt_record_value starts with auth-provider-organization-domain-verification and is shown once.
const detail = await fetch('/v1/platform/orgs/org_example/domains/odom_example', {
method: 'GET',
credentials: 'include'
})
const verified = await fetch('/v1/platform/orgs/org_example/domains/odom_example/verify', {
method: 'POST',
credentials: 'include',
headers: {
'X-XSRF-TOKEN': csrfToken
}
})
await fetch('/v1/platform/orgs/org_example/domains/odom_example/policy', {
method: 'PATCH',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfToken
},
body: JSON.stringify({
enrollment_mode: 'automatic_invitation'
})
})
const enrollment = await fetch('/v1/platform/orgs/org_example/domains/enrollment/check', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfToken
},
body: JSON.stringify({
email: 'person@example.com'
})
})
if (verified.data?.status === 'failed' || detail.data?.status === 'failed') {
await fetch('/v1/platform/orgs/org_example/domains/odom_example/retry', {
method: 'POST',
credentials: 'include',
headers: {
'X-XSRF-TOKEN': csrfToken
}
})
}
// failed domains can retry with a rotated TXT value; verified retry is a redacted no-op.
// Enrollment modes are manual, suggestion, automatic_invitation, and membership_request.
// enrollment.data.decision returns manual, suggestion, invitation, or membership_request.
// Wildcards, IPs, single-label domains, and common email providers are rejected.Hosted registration can return organization_enrollment when a verified domain policy produces suggestion, automatic invitation, or membership request decisions; manual and unverified domains stay silent.
const registration = await fetch('/v1/auth/proj_example/register', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfToken
},
body: JSON.stringify({
email: 'person@example.com',
password: 'CorrectHorseBatteryStaple1',
redirect_uri: 'https://app.example.com/verify'
})
})
// registration.data.organization_enrollment is returned only when a verified
// organization domain has an actionable suggestion, invitation, or
// membership_request decision. Unverified or manual domains fail closed.Managed organizations group project users for customer-application B2B access while provider organizations remain the dashboard tenant boundary.
const managedOrg = await fetch('/v1/platform/projects/proj_example/managed-organizations?organization_id=org_example', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfToken
},
body: JSON.stringify({
name: 'Acme Team',
slug: 'acme-team',
metadata: { plan: 'business' }
})
})
await fetch('/v1/platform/projects/proj_example/managed-organizations/morg_acme/domain-links?organization_id=org_example', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfToken
},
body: JSON.stringify({
organization_domain_id: 'odom_acme',
enrollment_action: 'membership_request'
})
})
await fetch('/v1/platform/projects/proj_example/managed-organizations/morg_acme/memberships?organization_id=org_example', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfToken
},
body: JSON.stringify({
managed_user_id: 'muser_123',
role: 'member',
status: 'active'
})
})
// Verified-domain domain-link helpers create only pending onboarding memberships.
// They do not grant active managed-organization membership automatically.
// Managed organizations are customer-application organizations.
// Provider dashboard organizations remain the management tenant boundary.
await fetch('/v1/auth/proj_example/managed-organizations/memberships', {
credentials: 'include'
})
await fetch('/v1/auth/proj_example/managed-organizations/memberships/morgm_invite/accept', {
method: 'POST',
credentials: 'include',
headers: { 'X-XSRF-TOKEN': csrfToken }
})
await fetch('/v1/auth/proj_example/managed-organizations/memberships/morgm_pending/decline', {
method: 'POST',
credentials: 'include',
headers: { 'X-XSRF-TOKEN': csrfToken }
})
// Hosted membership actions use the current managed-user session.
// They omit organization_id and management API keys.
// membership_request rows stay admin-reviewed.Generate a scoped one-time portal URL from the dashboard or trusted server, then let the hosted portal resolve safe setup metadata and set the HttpOnly cookie plus XSRF-TOKEN used for scoped portal mutations.
const link = await fetch('/v1/platform/orgs/org_example/portal-links', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfToken
},
body: JSON.stringify({
intent: 'enterprise_sso',
project_id: 'proj_example',
return_url: 'https://app.example.com/settings',
portal_path: '/portal'
})
})
// link.data.portal_url contains the one-time token once.
// The hosted /portal page resolves safe metadata and never returns token hashes.
// Resolve sets an HttpOnly cookie for the portal session plus an XSRF-TOKEN cookie.
// POST /v1/platform/portal/logout revokes the stored portal session, clears both portal cookies, and returns { data: { ok: true } }.
// The organization_settings intent can PATCH /v1/platform/orgs/{org}/portal/settings with credentials: 'include' and X-XSRF-TOKEN.
// Portal settings responses return organization settings only, never raw portal session tokens, token hashes, API keys, SCIM tokens, SSO secrets, or webhook secrets.Create SAML enterprise connections with normalized domains and a redirect URI that is already allowlisted on the project.
await fetch('/v1/platform/projects/proj_example/portal/enterprise-connections', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfToken
},
body: JSON.stringify({
name: 'Acme Okta',
provider_type: 'saml',
domains: ['acme.example'],
redirect_uri: 'https://app.example.com/sso/callback',
saml_metadata_xml: '<EntityDescriptor entityID="https://idp.example.com" />'
})
})
await fetch('/v1/platform/projects/proj_example/portal/enterprise-connections/sso_123/validate', {
method: 'POST',
credentials: 'include',
headers: { 'X-XSRF-TOKEN': csrfToken }
})
// Portal SSO mutations require the enterprise_sso Admin Portal session cookie.
// Responses omit OIDC client secrets, raw portal session tokens, token hashes,
// API keys, SCIM tokens, webhook secrets, and bearer-token material.Create a project directory to receive a one-time SCIM bearer token. Only the token hash is stored after creation or rotation.
const created = await fetch('/v1/platform/projects/proj_example/portal/scim-directories', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfToken
},
body: JSON.stringify({
name: 'Acme Okta',
provider: 'okta'
})
})
await fetch('/v1/platform/projects/proj_example/portal/scim-directories/dir_123/rotate-token', {
method: 'POST',
credentials: 'include',
headers: { 'X-XSRF-TOKEN': csrfToken }
})
// Portal Directory Sync mutations require the directory_sync Admin Portal session cookie.
// SCIM bearer tokens are returned only on create or rotate, stored only as hashes,
// and omitted from list responses, audit metadata, docs examples, and browser storage.Webhook endpoints subscribe to specific lifecycle events instead of receiving every event.
{
"url": "https://app.example.com/webhooks/auth",
"subscribed_events": [
"managed_user.created",
"managed_organization.membership_accepted",
"session.created",
"session.revoked"
]
}
// Known provider-emitted event labels are stable public names only.
// Custom dotted event names remain allowed for project-specific events.
// session.created and session.revoked carry a safe managed-user lifecycle payload:
// session_id, project_id, managed_user_id, status, device_name, ip_address,
// user_agent, authentication_method, created_at, updated_at, last_active_at, expires_at,
// revoked_at, ended_at, and optional MFA, SSO, social OAuth, magic-link,
// or safe impersonation summary fields. Platform dashboard sessions are
// internal and do not emit project webhook events.Security checklist
Hosted auth avoids browser token storage, requires CSRF for unsafe browser requests, and keeps redirects allowlisted.
Password length, session rotation, and recovery-token behavior are documented against modern identity guidance.
Tenant settings, privileged changes, webhook delivery, and audit trails are visible to operators for review evidence.