# Change an identity provider, keeping its sign-in URLs

PATCH

/v1/auth/providers/{providerId}

```sh
curl --request PATCH \
  --url https://example.com/v1/auth/providers/example \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data '{ "providerId": "example", "kind": "oidc", "displayName": "example", "domains": [ "example" ], "join": "invite", "metadata": {}, "issuer": "https://example.com", "clientId": "example", "clientSecretRef": "example", "scopes": [ "example" ], "authorizationEndpoint": "https://example.com", "tokenEndpoint": "https://example.com", "userinfoEndpoint": "https://example.com", "jwksEndpoint": "https://example.com", "claimMapping": { "userId": "example", "email": "example", "displayName": "example", "scopes": { "claim": "example", "delimiter": "example" }, "metadata": [ "example" ] }, "idpMetadataXml": "example", "idpEntityId": "example", "idpSsoUrl": "https://example.com", "idpCertificates": [ "example" ], "spSigningKeyRef": "example", "spDecryptionKeyRef": "example", "wantAssertionsSigned": true, "attributeMapping": { "userId": "example", "email": "example", "displayName": "example" } }'
```

Merges the changes into the stored provider and checks the result as a registration is (`400 invalid-provider-config`; `422 identity-provider-invalid` when the deployment can’t use it). The provider keeps its `signIn`, so nothing changes on the identity provider’s side. Not mounted when the deployment can’t update providers.

## Authorizations

- **[bearerAuth](https://docs.kindgi.com/v0.1.8/reference/api.md#bearerauth)**

## Parameters

### Path Parameters

**providerId**

required

string

\>= 1 characters

### Header Parameters

**Idempotency-Key**

string

\>= 1 characters

Caller-supplied idempotency key, scoped to the caller: the same key from someone else in the tenant is their own request (from 0.1.5). Retries with the same key return the original response byte-identical (per `docs/API-ROUTE-CONVENTIONS.md` §3.1). A retry sent while the first request still runs is answered `409 idempotency-key-in-flight` with `Retry-After`, on a runtime whose store holds keys (from 0.1.5); retry after it, and you get the first request’s answer. An answer that carries a secret (a new API key or public run token, a session token, a generated signing secret) isn’t kept: a retry gets `409 idempotency-key-replay-withheld`, with the first request’s status and when it succeeded (from 0.1.5).

## Request Bodyrequired

application/json

Changes to a registered identity provider: a field given replaces the stored one, `null` removes an optional one, and anything not given stays. The result must still be a whole provider of its `kind` (the fields `IdentityProviderConfig` requires for it), checked as a registration is. `providerId` and `kind` can’t change; `signIn` is the deployment’s and is ignored. A new `issuer` drops the endpoints discovered from the old one.

object

\>= 1 properties

**providerId**

Must match the path when given.

string

\>= 1 characters

**kind**

`oidc`: an OpenID Connect identity provider people sign in with (Okta, Entra ID, Google, Keycloak…); its endpoints come from its discovery document. `saml`: a SAML 2.0 identity provider people sign in with.

string

Allowed values: oidc saml

**displayName**

string | null

\>= 1 characters

**domains**

One of:

- **Array\<string>**

  Array\<string>

- **null**

  null

**join**

One of:

- **string**

  string

  Allowed values: invite domain

- **null**

  null

**metadata**

One of:

- **object**

  object

  **_key_**

  additional properties

  any

- **null**

  null

**issuer**

string format: uri

**clientId**

string

\>= 1 characters

**clientSecretRef**

Opaque reference resolved server-side. Never a plaintext secret.

string

\>= 1 characters

**scopes**

One of:

- **Array\<string>**

  Array\<string>

- **null**

  null

**authorizationEndpoint**

string | null format: uri

**tokenEndpoint**

string | null format: uri

**userinfoEndpoint**

string | null format: uri

**jwksEndpoint**

string | null format: uri

**claimMapping**

One of:

- **object**

  Per-provider claim mapping. All fields optional; closer to OIDC defaults (sub/email/name) → fewer overrides needed.

  object

  **userId**

  string

  \>= 1 characters

  **email**

  string

  \>= 1 characters

  **displayName**

  string

  \>= 1 characters

  **scopes**

  Claim path + optional delimiter for extracting Kindgi OAuth scopes from provider claims. When absent, scopes come from the token response `scope` field instead.

  object

  **claim**

  required

  string

  \>= 1 characters

  **delimiter**

  string

  **metadata**

  Array\<string>

- **null**

  null

**idpMetadataXml**

string | null

\>= 1 characters

**idpEntityId**

string | null

\>= 1 characters

**idpSsoUrl**

string | null format: uri

**idpCertificates**

One of:

- **Array\<string>**

  Array\<string>

- **null**

  null

**spSigningKeyRef**

string | null

\>= 1 characters

**spDecryptionKeyRef**

string | null

\>= 1 characters

**wantAssertionsSigned**

boolean | null

**attributeMapping**

One of:

- **object**

  object

  **userId**

  string

  \>= 1 characters

  **email**

  string

  \>= 1 characters

  **displayName**

  string

  \>= 1 characters

- **null**

  null

## Responses

### 200

Updated.

application/json

object

**providerId**

required

string

\>= 1 characters

**provider**

required

One of: discriminator: kind

- **object**

  An OpenID Connect identity provider people sign in with. The endpoints come from the issuer’s discovery document when absent, and are returned once the deployment has them.

  object

  **providerId**

  required

  string

  \>= 1 characters

  **displayName**

  The name a sign-in page shows (“Sign in with …”). Default: `providerId`.

  string

  \>= 1 characters

  **domains**

  The email domains whose people sign in with this provider (lowercase, e.g. `acme.com`): how an email-first sign-in page finds it.

  Array\<string>

  **join**

  Who may sign in the first time: `invite` (default) only people a tenant admin added; `domain` also anyone from one of `domains`, once the deployment has verified them.

  string

  Allowed values: invite domain

  **signIn**

  One of:

  - **object**

    object

    **redirectUri**

    required

    string format: uri

  - **object**

    object

    **spEntityId**

    required

    string

    \>= 1 characters

    **acsUrl**

    required

    string format: uri

    **spMetadataUrl**

    required

    string format: uri

  **metadata**

  object

  **_key_**

  additional properties

  any

  **kind**

  required

  string

  Allowed value: oidc

  **issuer**

  required

  string format: uri

  **clientId**

  required

  string

  \>= 1 characters

  **clientSecretRef**

  required

  Opaque reference resolved server-side. Never a plaintext secret.

  string

  \>= 1 characters

  **scopes**

  Default `openid email profile`.

  Array\<string>

  **authorizationEndpoint**

  string format: uri

  **tokenEndpoint**

  string format: uri

  **userinfoEndpoint**

  string format: uri

  **jwksEndpoint**

  string format: uri

  **claimMapping**

  Per-provider claim mapping. All fields optional; closer to OIDC defaults (sub/email/name) → fewer overrides needed.

  object

  **userId**

  string

  \>= 1 characters

  **email**

  string

  \>= 1 characters

  **displayName**

  string

  \>= 1 characters

  **scopes**

  Claim path + optional delimiter for extracting Kindgi OAuth scopes from provider claims. When absent, scopes come from the token response `scope` field instead.

  object

  **claim**

  required

  string

  \>= 1 characters

  **delimiter**

  string

  **metadata**

  Array\<string>

- **object**

  A SAML 2.0 identity provider people sign in with: its metadata XML, or its entity ID, single sign-on URL and signing certificates. Keys are given as references, never as keys.

  object

  **providerId**

  required

  string

  \>= 1 characters

  **displayName**

  The name a sign-in page shows (“Sign in with …”). Default: `providerId`.

  string

  \>= 1 characters

  **domains**

  The email domains whose people sign in with this provider (lowercase, e.g. `acme.com`): how an email-first sign-in page finds it.

  Array\<string>

  **join**

  Who may sign in the first time: `invite` (default) only people a tenant admin added; `domain` also anyone from one of `domains`, once the deployment has verified them.

  string

  Allowed values: invite domain

  **signIn**

  One of:

  - **object**

    object

    **redirectUri**

    required

    string format: uri

  - **object**

    object

    **spEntityId**

    required

    string

    \>= 1 characters

    **acsUrl**

    required

    string format: uri

    **spMetadataUrl**

    required

    string format: uri

  **metadata**

  object

  **_key_**

  additional properties

  any

  **kind**

  required

  string

  Allowed value: saml

  **idpMetadataXml**

  string

  \>= 1 characters

  **idpEntityId**

  string

  \>= 1 characters

  **idpSsoUrl**

  The IdP’s single sign-on URL (HTTP-Redirect binding).

  string format: uri

  **idpCertificates**

  The IdP’s signing certificates (PEM); several during a rollover.

  Array\<string>

  **spSigningKeyRef**

  Opaque reference to the service provider’s signing key, for IdPs that require signed AuthnRequests. Never a plaintext key.

  string

  \>= 1 characters

  **spDecryptionKeyRef**

  Opaque reference to the key that decrypts encrypted assertions. Never a plaintext key.

  string

  \>= 1 characters

  **wantAssertionsSigned**

  Require signed assertions. Default `true`.

  boolean

  **attributeMapping**

  Assertion attribute names. Defaults: `userId` = the NameID, `email` = `email`.

  object

  **userId**

  string

  \>= 1 characters

  **email**

  string

  \>= 1 characters

  **displayName**

  string

  \>= 1 characters

##### Example

```json
{
  "provider": {
    "join": "invite",
    "kind": "oidc"
  }
}
```

### 400

Malformed request body.

application/json

object

**error**

required

object

**code**

required

Stable machine-readable discriminant. Values match domain error codes (see `docs/API-ROUTE-CONVENTIONS.md` §4.3).

string

**message**

required

string

**details**

Optional, kind-specific.

object

**_key_**

additional properties

any

**requestId**

required

Server-assigned request id; also echoed via `X-Request-Id` header.

string

##### Examplegenerated

```json
{
  "error": {
    "code": "example",
    "message": "example",
    "details": {},
    "requestId": "example"
  }
}
```

### 401

Missing / malformed / expired / revoked bearer token.

application/json

object

**error**

required

object

**code**

required

Stable machine-readable discriminant. Values match domain error codes (see `docs/API-ROUTE-CONVENTIONS.md` §4.3).

string

**message**

required

string

**details**

Optional, kind-specific.

object

**_key_**

additional properties

any

**requestId**

required

Server-assigned request id; also echoed via `X-Request-Id` header.

string

##### Examplegenerated

```json
{
  "error": {
    "code": "example",
    "message": "example",
    "details": {},
    "requestId": "example"
  }
}
```

### 403

Not a tenant admin (`permission-denied`), or this deployment’s operator manages sign-in (`identity-providers-operator-managed`, `KINDGI_AUTH_TENANT_PROVIDERS=off`): only the deployment’s own token can change its providers.

application/json

object

**error**

required

object

**code**

required

Stable machine-readable discriminant. Values match domain error codes (see `docs/API-ROUTE-CONVENTIONS.md` §4.3).

string

**message**

required

string

**details**

Optional, kind-specific.

object

**_key_**

additional properties

any

**requestId**

required

Server-assigned request id; also echoed via `X-Request-Id` header.

string

##### Examplegenerated

```json
{
  "error": {
    "code": "example",
    "message": "example",
    "details": {},
    "requestId": "example"
  }
}
```

### 404

No identity provider registered with that id under this tenant.

application/json

object

**error**

required

object

**code**

required

Stable machine-readable discriminant. Values match domain error codes (see `docs/API-ROUTE-CONVENTIONS.md` §4.3).

string

**message**

required

string

**details**

Optional, kind-specific.

object

**_key_**

additional properties

any

**requestId**

required

Server-assigned request id; also echoed via `X-Request-Id` header.

string

##### Examplegenerated

```json
{
  "error": {
    "code": "example",
    "message": "example",
    "details": {},
    "requestId": "example"
  }
}
```

### 409

Idempotency-Key was reused with a different body, or resource-state conflict.

application/json

object

**error**

required

object

**code**

required

Stable machine-readable discriminant. Values match domain error codes (see `docs/API-ROUTE-CONVENTIONS.md` §4.3).

string

**message**

required

string

**details**

Optional, kind-specific.

object

**_key_**

additional properties

any

**requestId**

required

Server-assigned request id; also echoed via `X-Request-Id` header.

string

##### Examplegenerated

```json
{
  "error": {
    "code": "example",
    "message": "example",
    "details": {},
    "requestId": "example"
  }
}
```

### 413

The request body is over the API’s limit (`request-too-large`; `details.maxBytes` says how much).

application/json

object

**error**

required

object

**code**

required

Stable machine-readable discriminant. Values match domain error codes (see `docs/API-ROUTE-CONVENTIONS.md` §4.3).

string

**message**

required

string

**details**

Optional, kind-specific.

object

**_key_**

additional properties

any

**requestId**

required

Server-assigned request id; also echoed via `X-Request-Id` header.

string

##### Examplegenerated

```json
{
  "error": {
    "code": "example",
    "message": "example",
    "details": {},
    "requestId": "example"
  }
}
```

### 422

The deployment could not use the configuration (`identity-provider-invalid`).

application/json

object

**error**

required

object

**code**

required

Stable machine-readable discriminant. Values match domain error codes (see `docs/API-ROUTE-CONVENTIONS.md` §4.3).

string

**message**

required

string

**details**

Optional, kind-specific.

object

**_key_**

additional properties

any

**requestId**

required

Server-assigned request id; also echoed via `X-Request-Id` header.

string

##### Examplegenerated

```json
{
  "error": {
    "code": "example",
    "message": "example",
    "details": {},
    "requestId": "example"
  }
}
```

### 500

Server error (unmapped domain code or framework crash).

application/json

object

**error**

required

object

**code**

required

Stable machine-readable discriminant. Values match domain error codes (see `docs/API-ROUTE-CONVENTIONS.md` §4.3).

string

**message**

required

string

**details**

Optional, kind-specific.

object

**_key_**

additional properties

any

**requestId**

required

Server-assigned request id; also echoed via `X-Request-Id` header.

string

##### Examplegenerated

```json
{
  "error": {
    "code": "example",
    "message": "example",
    "details": {},
    "requestId": "example"
  }
}
```

## See also

- [`GET /v1/auth/providers/{providerId}`: Get one identity provider](https://docs.kindgi.com/v0.1.8/reference/api/operations/authprovidersget.md)
- [`GET /v1/auth/providers`: List identity providers configured for the tenant](https://docs.kindgi.com/v0.1.8/reference/api/operations/authproviderslist.md)
- [`POST /v1/auth/providers`: Register an identity provider (OIDC or SAML)](https://docs.kindgi.com/v0.1.8/reference/api/operations/authprovidersregister.md)
- [`GET /v1/auth/providers/{providerId}/sign-in`: What to give the identity provider, before or after registering](https://docs.kindgi.com/v0.1.8/reference/api/operations/authproviderssignin.md)
- [Error code `identity-provider-invalid`](https://docs.kindgi.com/v0.1.8/reference/errors.md#identity-provider-invalid)
- [Error code `identity-providers-operator-managed`](https://docs.kindgi.com/v0.1.8/reference/errors.md#identity-providers-operator-managed)
- [Error code `permission-denied`](https://docs.kindgi.com/v0.1.8/reference/errors.md#permission-denied)
- [Error code `request-too-large`](https://docs.kindgi.com/v0.1.8/reference/errors.md#request-too-large)
- [Every error code](https://docs.kindgi.com/v0.1.8/reference/errors.md)
