Update SSO Configuration

PUT /v1/sso/config/{id}

Edit an SSO connection on the caller's active account. Commonly used to rotate the IdP client secret, switch the OIDC endpoints, or toggle enforced.

This is a full replacement: send the same fields as create, and all of the same Req fields must be present. The one exception is client_secret — because GET endpoints never return the secret, leave it empty/omitted to keep the stored one, or pass a new value to rotate it.

Plan-gated: requires the sso entitlement on the account's plan. Permission-gated: the caller needs the settings:update account permission — members without it get 403.

Saving resets status to active and clears the last test result (last_error_message, last_tested_at); re-run test afterwards. Changing email_domain on an oidc/saml config resets domain verificationdomain_verified returns to false, a fresh DNS-TXT record is issued in the response, and the config stops applying at login until you re-run verify-domain. google/github stay auto-verified.

Path parameters

id int64 Req
SSO config ID. Must belong to the caller's active account (else 404).

Request body

Same fields as create. Notable behaviors on update:

client_secret string
Pass a new value to rotate; leave empty/omitted to keep the existing secret. Never returned by GET endpoints.
email_domain string Req
Lowercased server-side; unique per account (409 on collision). Changing it resets domain verification for oidc/saml configs.
provider_type string Req
google | github | oidc | saml. For google/github the auth_url/token_url/userinfo_url are force-locked to canonical endpoints; any supplied values are ignored.
auth_url, token_url, userinfo_url string
Required for oidc/saml. Must be HTTPS and public (SSRF-guarded).
enforced boolean
When true, matching users are forced through SSO and password login is rejected. Requires the account's plan to include the sso entitlement (else 403).

Response (200 OK)

The updated SSO config (SSOConfigResponse, secret never included). For an oidc/saml config whose email_domain changed, domain_verified is false and the response carries domain_verify_record_name / domain_verify_record_value — the TXT record to publish before calling verify-domain.

Errors

400 Bad Request
Missing required field, invalid provider_type, or non-HTTPS/private endpoint URL.
401 Unauthorized
Missing auth.
403 Forbidden
No active account, missing settings:update permission, plan lacks the sso entitlement, or enforced: true requested on a plan without SSO.
404 Not Found
Config doesn't exist or belongs to another account.
409 Conflict
Another config on this account already uses the new email_domain.
Request — rotate secret (full body)
curl -X PUT "https://api.ngris.com/v1/sso/config/1" \ -H "X-API-KEY: <your_api_key>" \ -H "Content-Type: application/json" \ -d '{ "email_domain": "acme.com", "provider_type": "oidc", "client_id": "0oa1234abc", "client_secret": "<new-client-secret>", "auth_url": "https://acme.okta.com/oauth2/default/v1/authorize", "token_url": "https://acme.okta.com/oauth2/default/v1/token", "userinfo_url": "https://acme.okta.com/oauth2/default/v1/userinfo", "scopes": "openid profile email", "enforced": false }'
Python
from ngris import Ngris client = Ngris(api_key="<your_api_key>") # Full replacement; omit client_secret to keep the stored one. client.sso.update("1", { "email_domain": "acme.com", "provider_type": "oidc", "client_id": "0oa1234abc", "client_secret": "<new-client-secret>", "auth_url": "https://acme.okta.com/oauth2/default/v1/authorize", "token_url": "https://acme.okta.com/oauth2/default/v1/token", "userinfo_url": "https://acme.okta.com/oauth2/default/v1/userinfo", })
Response — 200 OK
{ "id": 1, "account_id": 5, "email_domain": "acme.com", "provider_type": "oidc", "client_id": "0oa1234abc", "auth_url": "https://acme.okta.com/oauth2/default/v1/authorize", "token_url": "https://acme.okta.com/oauth2/default/v1/token", "userinfo_url": "https://acme.okta.com/oauth2/default/v1/userinfo", "scopes": "openid profile email", "status": "active", "enforced": false, "domain_verified": true, "last_error_message": "", "last_tested_at": null, "created_at": "2026-01-15T00:00:00Z", "updated_at": "2026-01-15T09:30:00Z" }
Iris