Update SSO Configuration
PUT
/v1/sso/config/{uuid}
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 config resets domain verification — domain_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
The SSO config's uuid. Must belong to the caller's active account (else 404).
Deprecated: the legacy integer id is still accepted in the path until the sunset, answered with Deprecation and Sunset headers. Use the uuid.
Request body
Same fields as create. Notable behaviors on update:
Pass a new value to rotate; leave empty/omitted to keep the existing secret. Never returned by GET endpoints.
Lowercased server-side; unique per account (409 on collision). Changing it resets domain verification for oidc configs.
google | github | oidc (saml returns 400: SAML is not supported). For google/github the auth_url/token_url/userinfo_url are force-locked to canonical endpoints; any supplied values are ignored.
Required for oidc. Must be HTTPS and public (SSRF-guarded).
Required for oidc (same as
create):
issuer is matched against the id_token
iss claim and
jwks_url supplies the signature keys at login. Cleared automatically for
google/
github. Switching a config to
oidc without both is rejected with 400. Use
Discover to auto-fill.
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 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.
Deprecated: until the sunset this response also carries the legacy integer id and *_id fields. Don't use them; read uuid and the *_uuid fields.
Errors
Missing required field, invalid provider_type, missing issuer/jwks_url for oidc, or non-HTTPS/private endpoint URL.
No active account, missing settings:update permission, plan lacks the sso entitlement, or enforced: true requested on a plan without SSO.
Config doesn't exist or belongs to another account.
Another config on this account already uses the new email_domain.
curl -X PUT "https://api.ngris.com/v1/sso/config/019af662-7814-75fe-ac3c-b767d84325a9" \
-H "X-API-KEY: <your_api_key>" \
-H "Content-Type: application/json" \
-d '{
"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",
"issuer": "https://acme.okta.com/oauth2/default",
"jwks_url": "https://acme.okta.com/oauth2/default/v1/keys",
"scopes": "openid profile email",
"enforced": false
}'
from ngris import Ngris
client = Ngris(api_key="<your_api_key>")
# Full replacement. client_secret is left out, so the stored one is kept;
# add "client_secret": "your-new-idp-client-secret" to rotate it.
client.sso.update("019af662-7814-75fe-ac3c-b767d84325a9", {
"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",
"issuer": "https://acme.okta.com/oauth2/default",
"jwks_url": "https://acme.okta.com/oauth2/default/v1/keys",
})
{
"uuid": "019af662-7814-75fe-ac3c-b767d84325a9",
"account_uuid": "019a68b9-1a79-7820-a884-41f554aba6bd",
"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",
"issuer": "https://acme.okta.com/oauth2/default",
"jwks_url": "https://acme.okta.com/oauth2/default/v1/keys",
"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"
}