---
title: "POST /orgs/{org_id}/identity-providers"
method: POST
path: "/orgs/{org_id}/identity-providers"
tags: ["orgs"]
---

# POST /orgs/{org_id}/identity-providers

`POST /orgs/{org_id}/identity-providers`

Create an SSO or directory identity connection for the organization.

## Path parameters

- `org_id` string, required

## Request body

- CreateIdentityProviderReqBody — Create an OIDC identity-provider connection for an org.
  - `allowed_domains` string[] — Email domains eligible for JIT auto-provisioning. Empty = no JIT.
  - `client_id` string, nullable — OAuth client id registered with the IdP. Required for `oidc`.
  - `client_secret` string, nullable — OAuth client secret. Sealed at rest with the org DEK; never returned. Required for `oidc`.
  - `default_role_id` integer, nullable — Optional catch-all role for JIT members whose group claim matched no mapping. When omitted, such members are added with no role (a bare member, pending an admin grant) rather than an implicit default. Accepts a number or a stringified id (`2227` or `"2227"`).
  - `display_name` string, nullable — Human-readable label for the login button / admin UI.
  - `enabled` boolean, nullable — Whether the connection is active. Defaults to true.
  - `groups_claim` string, nullable — Claim carrying group membership. Defaults to `groups`.
  - `issuer` string, nullable — IdP issuer / discovery base; `/.well-known/openid-configuration` is fetched from here. **Required for `oidc`; ignored for `directory`.**
  - `kind` 'oidc' | 'saml' | 'directory' — Which provider implementation drives a connection's login flow. Mirrors the `kind` CHECK in `db/init.sql`; widened additively as kinds ship (`oidc` first, `saml` later).
  - `provider_key` string, required — Stable, URL-safe handle used in the login URL (`/auth/sso/{provider_key}`) and the signed OAuth state. Lowercase letters/digits/hyphens; must not collide with the built-in social providers. Globally unique.
  - `scopes` string, nullable — Space-separated scopes. Defaults to `openid email profile`.

## Response `201`

Connection created

- IdentityProviderView — Masked view of a connection. Never includes the client secret.
  - `allowed_domains` string[], required
  - `client_id` string, nullable — OIDC client id. `null` for non-OIDC kinds.
  - `client_secret_set` boolean, required — Whether a client secret is configured. The secret itself is never returned.
  - `created_at` integer, required
  - `default_role_id` string, nullable — Catch-all role granted to JIT members with no matching group mapping. `null` = no catch-all role.
  - `display_name` string, nullable
  - `enabled` boolean, required
  - `enforced` boolean, required — Read-only here: SSO enforcement isn't configurable via the API yet.
  - `groups_claim` string, nullable
  - `id` string, required
  - `issuer` string, nullable — OIDC issuer. `null` for non-OIDC kinds (e.g. SAML), whose connection details live in kind-specific fields added when those kinds ship.
  - `kind` string, required
  - `org_id` string, required
  - `provider_key` string, required
  - `scopes` string, nullable
  - `updated_at` integer, required

## Other responses

- `409` — provider_key already in use

---

[API](https://skmtc.net/timbal-ai/apis/timbal-platform-api.md) · [All operations](https://skmtc.net/timbal-ai/apis/timbal-platform-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/timbal-ai/timbal-platform-api/versions/dd7e398ce0d3/schema)
