Skip to content
AXOWLDevelopers
Quickstart

IdP connections

Org-scoped (/api/org/{slug}/idp-connections, session-authenticated). Changes need the org.idp_connection.update scope (Owner and Admin hold it). An org can hold several active connections; each is routed by the sign-in email’s domain, and one connection with no domain acts as the default. A deactivated or replaced connection is kept as history, never deleted. Field names on this resource are snake_case.

named-okta, named-entra, named-google, named-axowl, named-kakao, named-naver, custom-saml, custom-oidc. Any other value answers 400 invalid_type with the allowed list. The named-* providers use the same OIDC payload/validation as custom-oidc — the brand label is preserved only for UI display.

Method · RoutePurpose
GET “connection (the default — no domain — else the newest) and connections[] (all active), plus limit (plan cap, -1 = unlimited) and used. OIDC client secrets are redacted (only oidc_client_secret_set is returned). Each connection also carries id, type, display_name, email_domain, attribute_mapping, its saml_* / oidc_* settings, last_synced_at, last_sync_error and created_at.
POST “Create or replace a connection (see rules below).
POST /deactivateSwitch back to Axowl native login — turns every active connection off.
POST /{connectionId}/deactivateTurn one connection off; the others keep routing. 404 connection_not_found for an unknown id.

type (required), display_name, email_domain (routing; omit for the default connection), attribute_mapping, and id to replace a specific existing connection.

  • OIDC (custom-oidc / named-*): oidc_discovery_url or manual oidc_issuer + oidc_authorization_endpoint + oidc_token_endpoint, plus oidc_client_id and oidc_client_secret (and optionally oidc_jwks_url). If a discovery URL is given, the well-known document is fetched and the issuer, endpoints and JWKS URL you left empty are filled in. Missing pieces answer 400 oidc_requires_discovery_or_manual_endpoints or 400 oidc_requires_client_id. A blank client secret on replace reuses the replaced connection’s secret.
  • Another Axowl organization as the IdP (named-axowl): set oidc_discovery_url to that organization’s staff IdP discovery URL, https://api.axowl.com/api/public/orgs/{idp-slug}/staff/.well-known/openid-configuration, and oidc_client_id / oidc_client_secret to a client created there under Organization settings → User management → Staff IdP with this organization’s Redirect URI. The secret is required. An app group OIDC client (customer sign-in, issuer …/orgs/{slug}) is rejected with 400 axowl_idp_not_staff — it would let that app’s customers sign in as staff.
  • PKCE: Axowl sends a PKCE challenge (S256) on every OIDC sign-in except Kakao and Naver, and sends code_verifier with the token request. Without a client secret the token request is sent only when PKCE is in use.
  • SAML (custom-saml): saml_metadata_url or saml_metadata_xml or manual saml_sso_url + saml_entity_id + saml_certificate (else 400 saml_requires_metadata_or_manual). A blank certificate on replace reuses the replaced connection’s.

Your organization can act as the company IdP for other services — another Axowl organization’s named-axowl connection, or any OIDC client. This is separate from the app group OIDC provider (/api/public/orgs/{slug}/authorize), which signs in an app’s customers; the staff IdP signs in your employees (active members of the organization).

MethodPath
List clientsGET/api/org/{slug}/staff-idp/clients (org.idp_connection.read)
Create clientPOST/api/org/{slug}/staff-idp/clients — { "name", "redirect_uri" } (org.idp_connection.update). The response carries client_secret once; only its hash is stored.
Delete clientDELETE/api/org/{slug}/staff-idp/clients/{clientId} (org.idp_connection.update)
DiscoveryGET/api/public/orgs/{slug}/staff/.well-known/openid-configuration
AuthorizeGET/api/public/orgs/{slug}/staff/authorize — response_type=code, exact redirect_uri match, optional PKCE (S256)
TokenPOST/api/public/orgs/{slug}/staff/token — client_secret_post or client_secret_basic (required); code_verifier when PKCE was used

Authorize sends the employee to the Axowl sign-in (skipped when already signed in), checks that the account is an active member of the organization, and returns a single-use code (60 s). The id_token (RS256, organization signing key, JWKS at /api/public/orgs/{slug}/.well-known/jwks.json) has iss = …/orgs/{slug}/staff, aud = client_id, sub (Axowl user id), email, email_verified, name, org_slug, type = "staff" and nonce, and lives 5 minutes. Deleting a client stops sign-in through it at once.

  1. Which row is replaced: the id you name → else the active connection with the same email_domain → else the default (no-domain) connection. An id that is not an active connection answers 404 connection_not_found. Only that row is deactivated; other customers’ SSO keeps working.
  2. A domain can route to one active connection only — 409 email_domain_in_use.
    • Attaching a new email_domain requires that domain to be verified first under Self SSO domains (DNS TXT) — otherwise 400 email_domain_not_verified. Re-saving a connection with the domain it already has is unaffected.
  3. Enterprise SSO needs the Pro plan or higher — 403 UPGRADE_REQUIRED (feature: "sso").
  4. Adding (not replacing) a connection counts against the plan cap — 403 UPGRADE_REQUIRED (feature: "sso_connections", with limit and current). Caps: Free 0 · Pro 1 · Pro+ 3 · Business 10 · Enterprise unlimited.
  5. named-kakao / named-naver require the Korean Package add-on — 402 ADDON_REQUIRED. Existing Kakao/Naver connections are not cut off by this gate; it guards creation and replacement only.

There is no direct IdP→IdP switch. To change providers you deactivate (all, or the one connection), then configure the new one — this prevents email-mapping lockout. After deactivation, /idp/{slug}/login returns idp_not_configured and native login is active. A login page can ask GET /idp/{slug}/login-hint beforehand to learn whether the org has an IdP and of which type (see OIDC SSO).