1. Docs
  2. API Reference
  3. Change an Environment's sign-in settings

Change an Environment's sign-in settings

PATCH/api/v1/auth-settings

Updates the sign-in settings of the request's Environment, applying any supplied fields (mfa, allow_self_signup, self_signup_require_captcha, login_require_captcha, password_login_enabled, email_otp_login_enabled, passkey_login_enabled, self_signup_daily_cap, access_token_ttl_seconds, refresh_token_ttl_days, public_refresh_token_ttl_days, allowed_web_origins, sso_return_urls, auth_links_base_url); omitted fields are left unchanged, allowed_web_origins are normalized and de-duplicated on save, and auth_links_base_url is canonicalized to a bare origin (send null to clear it). While auth_links_base_url is set, verification, password-reset and invitation emails link to that origin at /verify-email, /reset-password and /accept-invite instead of Canopy's hosted pages. Send the Environment's version (returned by the GET) in If-Match to refuse a stale save: a mismatch answers 409 version_mismatch, and without the header the check is skipped. Emits an environment.auth_settings_updated audit event naming the settings whose value changed.

Authentication

Bearer TokenAuthorization Option A

JWT access token. Never send alongside X-API-Key: a request carrying both is refused.

API KeyX-API-Key Option B

API key for management-tier access. Never send alongside an Authorization header: a request carrying both is refused.

Requires permission auth_settings.manageAuthentication

Change the Environment's sign-in settings. Held only when named: full access does not include it. A scoped API key must hold it as a scope; a full-access key holds every scope within its Environment except the named-only and account scopes; a developer's token needs the Console capability that covers it. A credential without it is refused with 403.

Headers

  • If-Match

    Optimistic-lock version of the resource. Send the `version` field returned on read; the server rejects with 409 if the row has changed since. Leave it out to skip the check; a header that names no version (not a whole number) is refused with 400 `if_match.invalid`.

  • X-Canopy-Environment

    The id of the Environment this request acts in. Required with an account API key, which belongs to the Account and names its Environment per request; an Environment key may send it only to name its own Environment. A missing header for an account key answers `400` (`api_key.environment_required`), one naming no Environment of the key's Account `400` (`api_key.environment_not_found`), and one naming another Environment than an Environment key's own `400` (`api_key.environment_mismatch`).

Request body

application/json

mfaobject Optional

MFA enforcement keys persisted under `env.settings`. Send the subset of keys you want to change; omitted keys retain their prior value.

allow_self_signupboolean Optional

Per-environment opt-in for browser-direct, publishable-key self-signup (`POST /v1/identity/auth/register`). Off by default; persisted under `env.settings.allow_self_signup`.

self_signup_require_captchaboolean Optional

Require a solved CAPTCHA on self-signup for this Environment. Off by default; persisted under `env.settings.self_signup_require_captcha`. The hosted sign-up page renders Canopy's proof-of-work widget by itself; a customer-built page must render `<canopy-captcha>` and send its `captcha_token`, or registrations will be refused.

login_require_captchaboolean Optional

Require a solved CAPTCHA on login for this Environment. Off by default; persisted under `env.settings.login_require_captcha`. The hosted sign-in page renders Canopy's proof-of-work widget by itself; a customer-built page must render `<canopy-captcha>` and send its `captcha_token`, or logins will be refused.

password_login_enabledboolean Optional

Enable password (email + password) login for this Environment. On by default; persisted under `env.settings.password_login_enabled`. Set false for a passwordless-only Environment.

email_otp_login_enabledboolean Optional

Enable passwordless email-OTP login for this Environment. Off by default (opt-in); persisted under `env.settings.email_otp_login_enabled`. When on, identities can sign in with an emailed 6-digit code via /login/email-otp/*.

passkey_login_enabledboolean Optional

Enable passkey sign-in for this Environment. Off by default (opt-in); persisted under `env.settings.passkey_login_enabled`. When on, an identity holding a passkey signs in with it alone via /login/passkey/*, and the passkey counts as its second factor.

self_signup_daily_capnumber Optional

Maximum self-signup registrations allowed per UTC day for this Environment. 0 (the default) means no cap. When exceeded, registration returns 429. Persisted under `env.settings.self_signup_daily_cap`.

range 0–100000

access_token_ttl_secondsnumber Optional

Lifetime in seconds of the access tokens (JWTs) this Environment issues to identities. Defaults to 900 (15 minutes). Persisted under `env.settings.access_token_ttl_seconds`; applies to tokens minted after the change.

range 60–3600

refresh_token_ttl_daysnumber Optional

Lifetime in days of the refresh tokens this Environment issues to identities — effectively how long a session survives without re-authentication. Defaults to 180. Persisted under `env.settings.refresh_token_ttl_days`; applies to tokens minted after the change.

range 1–365

public_refresh_token_ttl_daysnumber Optional

Lifetime in days of a public client's session (a single-page or mobile app with no client secret), counted from sign-in and never extended by a refresh: when it ends the person signs in again. Defaults to 30. Confidential clients keep `refresh_token_ttl_days`, which slides forward on each refresh. Persisted under `env.settings.public_refresh_token_ttl_days`; applies to sessions signed in after the change.

range 1–90

m2m_access_token_ttl_secondsnumber Optional

Lifetime in seconds of the access tokens a machine client obtains with `client_credentials`. Defaults to 300 (5 minutes). A machine token has no refresh, so this is how long a client keeps acting after its secret is rotated or it is disabled. Persisted under `env.settings.m2m_access_token_ttl_seconds`; applies to tokens minted after the change.

range 60–3600

m2m_default_audiencestring Optional

The audience a machine client's token names when the request sends no `audience`: the identifier of your API, which checks `aud` when it verifies the token. A client may also request any audience it lists in `allowed_audiences`. `null` clears it, after which a request must name an audience.

max length 2048

organization_integrations_enabledboolean Optional

Whether an organization's administrators (an identity holding `canopy:organization.manage` at the organization node) may create machine clients of their own, its integrations, pinned to that organization. Off by default. An integration always requests the Environment's `m2m_default_audience` and holds only roles from `organization_integration_role_ids`, so turning this on without both, or clearing either while it is on, is refused with `400 environment.integrations_audience_required` or `400 environment.integrations_roles_required`.

organization_integration_role_idsstring[] Optional

The roles an organization's administrators may give its integrations, by id: active roles of this Environment, shared by every organization (not one organization's own), carrying neither `canopy:organization.manage` nor `canopy:access.manage`; anything else is refused with `400 environment.integration_role_invalid`. Separate from `idp_arrival_roles`. Replaces the list. While `organization_integrations_enabled` is on the list cannot be empty (`400 environment.integrations_roles_required`). Removing a role leaves integrations already holding it unchanged; a deleted role leaves the list.

allowed_web_originsstring[] Optional

Browser Origins allowed to call this Environment's public identity-auth API cross-origin (CORS), e.g. `https://app.example.com`. Required to use the Direct-API flow from a browser SPA; empty means no browser client is permitted (server-to-server with an API key is unaffected). Persisted under `env.settings.allowed_web_origins`.

sso_return_urlsstring[] Optional

Allowlist of return URLs for publishable-key (Direct-API) SSO. After the IdP round-trip, `/v1/identity/auth/sso/*` redirects back to one of these with a single-use `sso_token`; an unregistered return URL is rejected (exact match — no open redirect). Persisted under `env.settings.sso_return_urls`.

idp_arrival_rolesobject Optional

The roles a customer's identity provider may grant and the one a newcomer arrives with, inherited by every organization in this Environment that has no grantable list of its own. Setting it opens directory sync for those organizations and is what the organization portal's SSO setup preselects. Refused with `409` when a withdrawn role is still mapped by an inheriting organization's directory, or when clearing it would leave an inheriting live directory with no arrival role. `null` clears it.

auth_links_base_urlstring Optional

Bare origin (https, or http on localhost) that auth-email links point at. Takes precedence over the Account's hosted pages. `null` clears it.

initiate_login_uristring Optional

The route in your application that starts a sign-in by sending the person to Canopy's `/oauth/authorize`. Canopy's hosted pages that end with nothing to return to (an accepted invitation, a verified email, a finished password reset) offer it as **Sign in** when the OAuth client involved names no `initiate_login_uri` of its own. https, or http on localhost. `null` clears it.

organizations_create_on_signupboolean Optional

Create an organization for every self-signup through `POST /v1/identity/auth/register` and add the new identity as its first member. Off by default; persisted under `env.settings.organizations_create_on_signup`. The organization starts with roles copied from the Environment's organization role templates, and the new identity holds its copy of the default admin template. Requires the organizations container and a default admin template; refused with `400 role_template.default_admin_missing` while there is none.

organizations_membership_requiredboolean Optional

Refuse a session to any identity that belongs to no organization in this Environment, at login, refresh and SSO completion, with `403 auth.organization_membership_required`. Off by default; persisted under `env.settings.organizations_membership_required`. Requires the organizations container. Identities already in no organization are refused from the next session issuance on.

Responses

application/json

  • dataEnvironmentAuthSettingsResponseDto*

application/json

  • errorApiErrorBodyDto*

application/json

  • errorApiErrorBodyDto*

application/json

  • errorApiErrorBodyDto*

application/json

  • errorApiErrorBodyDto*

Errors

When the request can't be completed, the response body includes a stable error code you can branch on, and a correlation_id (also sent as the X-Correlation-Id header). Quote the correlation id when you contact support: it identifies the exact request in Canopy's logs. A request refused by an authorization check answers 403 with the code authorization.denied, and its data names the denial_reason and the permission checked.

403authorization.deniedForbidden
When it happens

The credential does not hold the permission this operation checks: a scoped API key without the scope, a developer without the Console capability that covers it, or a permission granted somewhere other than the node the request targets. The error's data names the permission.

Remediation

Add the permission named in the Authentication section to the key's scopes, or ask an account administrator to grant the covering capability, then retry. For a node-scoped operation, make sure the grant reaches the node you are acting on.

Returned object

Request
curl -X PATCH "https://auth.canopy-io.com/api/v1/auth-settings" \
  -H "If-Match: "3"" \
  -H "X-Canopy-Environment: value" \
  -H "X-API-Key: $CANOPY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "mfa": {
      "mfa_required": false,
      "mfa_grace_period_days": 0,
      "mfa_trusted_device_days": 0,
      "mfa_factor_allowlist": [
        "totp"
      ],
      "mfa_after_sso": "exempt",
      "webauthn_rp_id": "acme.com",
      "webauthn_origins": [
        "https://portal.acme.com"
      ]
    },
    "allow_self_signup": false,
    "self_signup_require_captcha": false,
    "login_require_captcha": false,
    "password_login_enabled": false,
    "email_otp_login_enabled": false,
    "passkey_login_enabled": false,
    "self_signup_daily_cap": 0,
    "access_token_ttl_seconds": 0,
    "refresh_token_ttl_days": 0,
    "public_refresh_token_ttl_days": 0,
    "m2m_access_token_ttl_seconds": 0,
    "m2m_default_audience": "https://api.example.com",
    "organization_integrations_enabled": false,
    "organization_integration_role_ids": [
      "string"
    ],
    "allowed_web_origins": [
      "string"
    ],
    "sso_return_urls": [
      "string"
    ],
    "idp_arrival_roles": {
      "role_ids": [
        "string"
      ],
      "default_role_id": "string"
    },
    "auth_links_base_url": "https://app.example.com",
    "initiate_login_uri": "https://app.example.com/login",
    "organizations_create_on_signup": false,
    "organizations_membership_required": false
  }'
Response
{
  "data": {
    "environment_slug": "string",
    "version": 0,
    "mfa_required": false,
    "mfa_grace_period_days": 0,
    "mfa_trusted_device_days": 0,
    "mfa_factor_allowlist": [
      "string"
    ],
    "mfa_after_sso": "exempt",
    "webauthn_rp_id": "string",
    "webauthn_origins": [
      "string"
    ],
    "allow_self_signup": false,
    "self_signup_require_captcha": false,
    "login_require_captcha": false,
    "password_login_enabled": false,
    "email_otp_login_enabled": false,
    "passkey_login_enabled": false,
    "self_signup_daily_cap": 0,
    "access_token_ttl_seconds": 0,
    "refresh_token_ttl_days": 0,
    "public_refresh_token_ttl_days": 0,
    "m2m_access_token_ttl_seconds": 0,
    "m2m_default_audience": "string",
    "organization_integrations_enabled": false,
    "organization_integration_role_ids": [
      "string"
    ],
    "allowed_web_origins": [
      "string"
    ],
    "sso_return_urls": [
      "string"
    ],
    "idp_arrival_roles": {
      "role_ids": [
        "string"
      ],
      "default_role_id": "string"
    },
    "auth_links_base_url": "string",
    "initiate_login_uri": "string",
    "organizations_create_on_signup": false,
    "organizations_membership_required": false,
    "identities_without_organization_count": 0
  }
}
Related endpoints
GETGet an Environment's sign-in settings
Was this page helpful?

Tell us how we can improve this guide.