Admin
Connecting an Identity Provider
Wire Auth0, Clerk, Okta, WorkOS, or any OIDC provider so Alter can resolve users from their JWTs — and sync the full user directory.
The identity provider (IDP) is the external service that authenticates the app’s end users. Once one is configured, Alter verifies the JWTs the IDP issues, resolves which user is making each call, and looks up that user’s grants automatically.
Identity providers are included on every plan. One IDP per app. Skip this page for backend-only apps that never see end users.
Choose the right values
Section titled “Choose the right values”You normally do not create sub. Your identity provider creates a stable
subject for each user. In Alter’s User ID Claim, enter the claim name
sub, not a particular user’s subject value. Audience takes a value
identifying your application or API, not the word aud.
| Alter field | Meaning | Where to get it / what to enter |
|---|---|---|
Issuer URL (iss) | Who issued the token | Copy the provider’s issuer for the chosen tenant/environment/authorization server. Enter the issuer itself, without /.well-known/...; Discover obtains its signing-key URL. It must match the token’s iss, including any issuer path. |
| User ID Claim | Which claim identifies the user | Usually sub. The provider emits a different stable value for each user. Do not enter an email, user_…, 00u…, client ID, or audience here. Keep the default unless your token contract explicitly uses another stable top-level claim. |
Audience (aud) | Which application/API may accept the token | Enter the exact registered API audience or token-template audience used by tokens your app sends to Alter. It is not a callback URL, issuer URL, or user ID. For sign-in only, leave it blank and configure the wallet client pair. See the provider-specific recipes below. |
| Wallet Client ID | The OIDC application used for sign-in | Create a web/confidential OIDC application at the provider and copy its generated Client ID. Its ID tokens use that Client ID as their aud; Alter includes it in the accepted audience set when configured before locking. |
| Wallet Client Secret | Authenticates that OIDC application | Copy the secret from the same application as the Client ID. A management API key or webhook signing secret is a different credential and does not belong here. |
| Group Claim / Role Claim | Which top-level claims carry group memberships / roles | Enter claim names such as groups or org_id, not 00g…, org_…, or admin. Configure the provider to emit those claims in the token type you actually use. Dot notation such as o.id is not a nested-claim lookup. Leave unused mappings blank. |
| Group claim emits stable group IDs | Whether group values match directory/webhook IDs | Enable only when the claim emits immutable IDs (for example 00g… or org_…), not names or role labels. Follow the provider’s group-grant recipe below. |
For example, this illustrative decoded ID-token payload:
{ "iss": "https://tenant.example.com", "sub": "user_123", "aud": "oidc_client_456", "groups": ["group_789"]}maps to Issuer URL https://tenant.example.com, User ID Claim sub,
Wallet Client ID oidc_client_456, and Group Claim groups. For a
sign-in-only setup with the client secret supplied, Audience can be blank.
If the application also sends an access token with aud: "https://my-api.example",
register that API audience at the provider and enter https://my-api.example
in Audience before first use. These example values are placeholders, not
credentials or a working issuer.
Create or find an audience at each provider
Section titled “Create or find an audience at each provider”| Provider | Subject (sub) | Audience and client setup |
|---|---|---|
| Auth0 | Generated for each user, commonly `auth0 | …; keep User ID Claim = sub`. |
| Okta | ID-token sub is the stable Okta user ID (00u…); keep User ID Claim = sub for sign-in. Custom-server access-token sub can instead be the login/email, while uid carries the stable ID: inspect the actual token before choosing an access-token mapping. | Security → API → Authorization Servers → your custom server → Settings: copy its Audience (often api://default, but use your actual value) and Issuer URI. For org-server sign-in, use the bare org issuer, leave Audience blank, and supply the OIDC web application’s Client ID/Secret. Org-server access tokens are intended for Okta APIs, not third-party validation. |
| Clerk | Generated user_…; keep User ID Claim = sub. | For OAuth/OIDC sign-in, create OAuth applications → Add OAuth application in the intended instance, copy Client ID/Secret, and leave Audience blank. If your app sends a custom JWT template, JWT Templates → your template → Claims: add "aud": "your-app-audience", preserve the generated sub, and enter that same audience value in Alter. Request that named template in your app; editing a template does not automatically change OAuth ID tokens or ordinary session tokens. |
| WorkOS | Generated AuthKit user_…; keep User ID Claim = sub. | Use the AuthKit domain issuer. For Connect user access tokens, copy the actual aud: the requested resource indicator (API/MCP server URL), or the environment Client ID from API Keys when no resource is requested. Separately create a confidential Connect → Applications application and put its Client ID/Secret in the wallet fields; that client ID is the ID-token audience. These are two different client IDs. For sign-in only, Audience can be blank with wallet credentials. |
| Custom OIDC | Keep sub when it is the provider’s stable subject. | Create a web/confidential client using your provider’s instructions. For sign-in only, use its Client ID/Secret with Audience blank. For other tokens, register an API/resource audience at that provider and copy the exact issued value. |
Check token types separately. ID tokens and access tokens may have different
sub, aud, and group claims. A single Alter User ID Claim must identify the
same person consistently across the flows you enable. Do not switch it to an
email claim to make a failing test pass, or assume an access-token uid exists
in an ID token. Verify this in a separate test app before the first real user
locks the mapping. For Okta, start with the standard ID-token sign-in flow;
if forwarding custom-server access tokens too, configure the access-token subject
before enabling that flow:
- In Security → API → Authorization Servers → your server → Claims, edit the default sub claim’s access-token mapping.
- Set the expression to
user.getInternalProperty("id")so it emits the stable00u…ID. Keep Alter’s User ID Claim set tosub. - Use Token Preview for the assigned user and OIDC application. Confirm the
access token’s
subanduidequal the ID token’ssub, then verify newly issued tokens in your test app. Changing a shared authorization server affects its other clients too; use a dedicated test server to validate the change.
Okta documents both editing the subject mapping and the stable user-ID expression.
These meanings follow OpenID Connect’s ID-token contract, Auth0’s API audience guidance, and Okta’s distinction between org and custom authorization servers.
What gets configured
Section titled “What gets configured”Four layers. Only the first is required to verify tokens; the second is also required to sign users in (Wallet, app.authenticate()) and for users to approve delegations to agents:
- JWT verification — issuer URL, JWKS URL, audience, claim mappings.
- OIDC sign-in — adds a sign-in flow for
app.authenticate(), the Wallet, and approving Connect delegations to agents. - Webhook deprovisioning — real-time revocation when the IDP deletes or suspends a user, removes a group member, or deletes a group.
- Directory sync — bulk-imports users and groups from the IDP’s management API and keeps them reconciled on a schedule.
Saving an identity provider fetches the issuer’s OIDC discovery document and rejects the configuration if the document asserts a different issuer than the one entered (per OIDC Discovery §4.3). The same check runs on the pre-save discovery preview, so a mistyped or re-pointed issuer fails at save time rather than at the first token verification.
Sign-in modes
Section titled “Sign-in modes”What the application can do with its users depends on whether layer 2 is configured. Decide this before writing sign-in code:
| Mode | Configured | Sign users in with | Alter Wallet |
|---|---|---|---|
| JWT verification only | Layer 1 (issuer, audience, claims) | The identity provider’s own SDK; pass its token to Alter with user_token / userToken or verify_user_token() / verifyUserToken() | Not available |
| Sign-in client | Layers 1 and 2 (adds the sign-in client ID and secret) | app.authenticate(), create_auth_session() / createAuthSession(), or the identity provider’s own SDK | Available |
The configuration itself is read in the dashboard only. A coding agent working through the CLI or the MCP server cannot read it, so it should ask the operator which mode applies, or call create_auth_session() / createAuthSession(): an identity provider without a sign-in client answers HTTP 400 no_wallet_client (an application with no identity provider answers no_idp_configured). To move from JWT verification to a sign-in client, add the client ID and secret to the identity provider in the dashboard.
Audience binding
Section titled “Audience binding”Every active identity-provider configuration must bind tokens to this application. A token’s aud claim must match one of the accepted audiences:
- the explicit Audience field — what access tokens carry, and/or
- the Wallet OIDC Client ID — what OIDC ID tokens (used by Wallet sign-in) always carry; they never carry the API audience.
A token-validation-only configuration requires an explicit Audience; interactive OIDC defaults the accepted audience to the Client ID. When both are configured, a token matching either value is accepted. The rules:
- Tokens bound to neither value are rejected on every verification path, as are tokens listing additional recipients — with one exception: the issuer’s own
/userinfoendpoint may accompany an accepted audience (Auth0, for example, adds it to access tokens issued with theopenidscope). - The accepted set locks the first time a user is resolved from a token the provider issued. After that, any change that alters the set of accepted audiences is rejected. Adding a Wallet Client ID to a locked provider that already has an Audience is accepted but does not join the set: the client is stored for approving delegations only. Two changes survive the lock: one that leaves the set identical, and one that gives a binding to a configuration that has none at all — nothing validates today, so gaining one can only restore service.
- WorkOS is the one provider-specific carve-out. Some WorkOS tokens omit
aud, and the WorkOS issuer is scoped to a single environment (the environment Client ID is embedded in the native issuer path, and an AuthKit domain identifies one environment), so Alter permits an absentaudfor these WorkOS profiles. Connect user access tokens carrying anaudmust match the requested resource indicator, or the environment Client ID when no resource is requested; ID tokens must match the Connect application Client ID. The absent-claim exception never bypasses validation of a present audience. - Legacy configurations with neither value fail closed. Open User Authentication (OIDC) on the provider and save the required JWT audience — this repair remains available after users have signed in.
What to enter in the Audience field, per provider
Section titled “What to enter in the Audience field, per provider”| Provider | Audience field |
|---|---|
| Auth0 | Set it to the registered API identifier (Auth0 → Applications → APIs) when the application sends Alter Auth0-issued access tokens. Auth0 has no default audience and validates the value at sign-in — an unregistered value fails every sign-in with Service not found. For Wallet sign-in alone, leave it blank: the parameter is then not sent, and the Wallet OIDC Client ID becomes the accepted audience. |
| Okta | Depends on the authorization server behind the issuer. Custom authorization server (issuer https://<org>.okta.com/oauth2/<id> — recommended): set it to the server’s Audience — api://default on the default server. Org authorization server (no /oauth2/... path): leave it blank and configure Wallet sign-in — org-server ID tokens carry the OIDC Client ID as their aud, never api://default. |
| Clerk | Leave it blank for Wallet sign-in. Set it only if the app sends Alter tokens minted by a Clerk JWT template with a custom aud, and paste that exact value. Clerk never receives the audience at sign-in, so this field cannot break sign-in either way. |
| WorkOS | For Connect user access tokens, set Audience to the requested resource indicator, or to the environment Client ID from API Keys when no resource is requested. Set Wallet Client ID to the separate Connect application Client ID for ID tokens. For sign-in only, Audience can be blank with wallet credentials. A present aud must match; only tokens without that claim use the WorkOS issuer-binding exception. |
| Custom OIDC | Set it if the provider issues an aud you control; leave it blank to accept the Wallet Client ID; clear it if the provider rejects unregistered audience values it gives you no way to register (see Clearing the audience). |
Clearing the audience
Section titled “Clearing the audience”Some providers validate the audience parameter against their own registered list, offer no way to register one, and then fail every sign-in with an error like:
Requested audience "your-value" has not been whitelisted by the OAuth 2.0 Client.The exact wording comes from the provider — treat it as illustrative, not a string to match on. The remedy: open User Authentication (OIDC) on the provider, empty the JWT audience field, and save. The audience is then not sent at all, and sign-in validates the ID token against the Client ID — the standard OIDC behaviour. This mainly applies to custom OIDC deployments (for example self-hosted Ory Hydra). For Clerk no clearing is ever needed: Alter recognizes Clerk issuers and never sends the audience parameter at sign-in, so a configured audience only adds an accepted token audience.
Clearing follows the binding rules above:
- The Wallet OIDC Client ID must remain set — it becomes the sole accepted audience. Clearing both is rejected while the provider is active, because an active provider with no binding would reject every token it issues. A disabled provider may be left without a binding — disabling is always the safe way to take a misconfigured provider out of service — but it cannot be re-activated until a binding is set again.
- On a locked provider, clearing is allowed only when it leaves the set of accepted audiences unchanged. The common case is an Audience that already holds the same value as the Wallet OIDC Client ID — removing it changes nothing, so it is allowed. The same rule governs removing the wallet credentials.
Audience verification at save time
Section titled “Audience verification at save time”Saving checks the configured audience against the provider before the configuration is stored. Providers differ: Auth0 validates the parameter at sign-in and refuses an unrecognized value (breaking sign-in for every user), Okta and WorkOS ignore a parameter they do not recognize, and Clerk never receives it at all. The check can prove that a provider rejects an audience; it can never prove acceptance — some providers only evaluate the audience after the user has signed in. Three outcomes, all returned on the save result; the portal and alter identity-providers create surface the two that need attention:
| Outcome | What it means |
|---|---|
| Nothing to verify | No audience is configured (the Wallet OIDC Client ID is the token audience), or the provider never receives an audience at sign-in (Clerk). A complete configuration — no notice is shown. |
| Not verified | The check could not complete, or wallet sign-in credentials are not configured yet so there was no client to check with. The configuration was saved — confirm it with a test sign-in. |
| Rejected | The provider identified the audience as unregistered or not authorized for this application. |
A save that sets the audience (or the Wallet Client ID it is checked against) and gets a rejection is blocked — nothing is stored, and the error names the provider’s own reason. A save that touches neither value — say, a group-claim change on a provider whose stored audience is already bad — goes through, with the rejection reported on the result, so unrelated settings stay fixable while the audience is corrected. Placeholder values are the common cause: an audience like test is accepted by the form but rejected by the provider. Fix a rejection by setting a registered, authorized identifier — or clear the field (above).
Verify the setup before rollout
Section titled “Verify the setup before rollout”Saved is not end-to-end verified. Save fetches discovery, checks the advertised
issuer, and probes configured sign-in credentials and audience. Some probes can
be inconclusive and still save with a notice. connect_delegation_signin_configured
means the necessary fields and issuer capability are present; it is not a record
of a successful login. Saving a webhook secret does not prove event delivery, and
saving a directory credential does not prove a complete import.
- Prepare a separate test app and disposable user. Complete issuer, claim mappings, audience, client credentials, and group-ID mode before resolving any token. Discovery and directory import alone do not lock the provider; successful token resolution does, including a token-verification API call.
- Register callbacks and allow the user. Copy the SDK callback, Wallet callback, and supported logout URLs shown in Alter into the corresponding provider fields exactly. Assign the user to the Okta application, enable the Auth0 connection, or apply the corresponding Clerk/WorkOS access settings. Exercise your intended MFA policy; do not disable MFA to make setup pass.
- Complete the real flows you use. Test SDK authentication, Wallet login, and an agent delegation approval. Confirm the callback completes and the correct user appears in Alter. An authorize redirect or a provider login page alone is not success.
- Verify identity and memberships. Inspect a test token locally; do not
paste real tokens into public decoders or tickets. Check
iss,sub,aud, group/role claims, and token type. In Alter, confirm the expected user, groups, and test access. Exercise both token types if your app uses both. - Verify directory sync, if enabled. Save the separate management credential with the scopes in the provider recipe, run Directory Import, and check the completion status plus expected users, groups, and memberships. A valid OIDC client secret is not a directory management credential.
- Verify webhooks, if enabled. Subscribe to the exact listed events. Remove a disposable test membership or user at the provider, check its real delivery log and Alter’s webhook status, and confirm the related test access is revoked. A webhook verification challenge or a successful HTTP response alone does not demonstrate deprovisioning. Restore the disposable fixture through its normal provisioning flow after checking the result.
Correct a setup without losing access
Section titled “Correct a setup without losing access”- Before locking: set claim mappings in Add Identity Provider before saving. The portal’s existing-provider card displays these mappings; to correct a saved mapping through the UI, recreate the unused provider before onboarding users. Deletion also removes any users already imported from the directory. Audience and sign-in credentials are editable under User Authentication (OIDC). Repeat verification after corrections. The CLI creates providers; it does not update or delete their trust configuration.
- Bad secret, callback, assignment, or MFA setup: correct that setting and retry. Rotate the client secret for the existing client in Alter; update the callback allowlist, connection/assignment, or policy at the provider. These fixes do not require replacing the IDP.
- Locked issuer, claim mappings, group-ID mode, or accepted audience set: there is no unlock button. First validate the replacement in a separate app. Record configuration and the users/groups/grants to restore, arrange the access interruption, then use the portal’s Force delete and recreate the provider. Force delete deprovisions users and revokes their grants; recreation is not a migration and does not restore access automatically. Provision and grant access again, then repeat verification. Exceptions that preserve the accepted audience set are explained under Audience binding.
Approving Connect delegations
Section titled “Approving Connect delegations”A delegation to an agent is approved only with proof that comes from the user, never on the strength of a token: the application that requested the delegation holds the Connect session token, and usually the user’s own token too. On Connect, the proof is a sign-in Alter runs against this identity provider, in the browser that approves, before the page offers Approve:
- every managed-secret Connect session asks for it;
- an OAuth Connect session created with an agent asks for it on the one-click shortcut for an account the user already connected. Connecting an account at the provider is itself the user’s proof of the connection, so that path needs no sign-in to connect;
- either OAuth path asks for it before the user chooses whether the agent may share the access with other agents (a session created with
delegable): the confirmation screen after a provider login shows Sign in to choose first. That choice is the user’s alone, and the Connect session token that would otherwise stand for the user is also held by the application that asked.
The same applies in the Wallet: delegating to an agent needs proof of the user’s own Wallet sign-in, not only a token.
This needs the OIDC sign-in layer: the Client ID and Client Secret, with the SDK callback URL registered (the approval sign-in returns there). The provider card shows whether users can approve delegations, and alter identity-providers create reports it in connect_delegation_signin_configured. Without it:
- requesting a managed-secret delegation fails with
idp_signin_not_configured(HTTP 409, not retryable). Its reason names the fix:missing_client_idormissing_client_secret— add the sign-in Client ID and Client Secret;issuer_cannot_sign_in— the issuer can validate tokens but not sign users in (a WorkOS native AuthKit issuer, for example), so use an issuer that supports OpenID Connect sign-in (on WorkOS, the Connect issuer); - an OAuth Connect session with an agent skips the already-connected shortcut and sends the user through the provider’s own authorization instead;
- an OAuth Connect session that asks for onward sharing offers the user no sharing choice: a new delegation is created as one the agent cannot share onward, and an existing delegation keeps its setting.
A failed sign-in never ends the request. If the user cancels at the identity provider, signs in as a different account, or the result cannot be verified, nothing is granted and the page says why; the user can sign in again — after a wrong account, Use a different account forces a fresh sign-in — or cancel. The application is told only the outcome (approved, cancelled, or ended without an answer), never a sign-in failure. Cancelling needs no sign-in, so a user can always decline.
Every user who should approve delegations must be allowed to sign in through the sign-in client: assign them to the Okta app integration, enable their connection on the Auth0 application, and lift any user-assignment requirement on a custom OIDC client. When the user already has a session at the identity provider, the sign-in is a silent redirect. To require a fresh password or MFA prompt for approvals, configure it at the identity provider (for example, an authentication or sign-on policy on the sign-in client).
What the sign-in proves. That the person in that browser could sign in to this identity provider as the user the request is for — no more. The proof is only as strong as the identity provider’s control over its users: anyone who administers the identity provider’s tenant, and can sign in as a user, impersonate one, or reset a password, can complete it. Treat administration of the identity provider as part of who can approve delegations, and use its MFA and session policies where approvals need a stronger guarantee.
What the audit trail records. Each Connect approval row records how the user proved it, when the identity provider authenticated them (auth_time), the authentication methods and context class the identity provider reports (amr, acr), and which application or agent asked. A Wallet delegation row records the Wallet sign-in proof, when it was verified, and auth_time; it carries no amr or acr. A cancel row records whether the person who cancelled had signed in (approver_verified). A refusal — a call from a browser that has not signed in, or a sign-in that did not prove the user — names no user, because nobody proved to be that user; the request’s user is recorded separately as subject_app_user_id.
Apps should open Connect URLs in the system browser — a popup or redirect on the web, and the system browser (not an embedded WebView) in a native app. Identity providers refuse or cannot share their sign-in session with embedded WebViews, and an app that controls a WebView could drive the approval itself.
Troubleshooting a Connect popup that never completes. A managed-secret Connect session writes a delegation.session_created audit row when it is created; an OAuth Connect session writes none. Every approval sign-in writes an identity.signin_terminal row, and it, the approval and cancel rows, and (for a managed secret) the session row all carry the same connect_session_id, so filter on connect_session_id to follow one request. A request with no identity.signin_terminal row never came back from the identity provider, or the user never started the sign-in — most often the SDK callback URL is not registered with the sign-in client (the identity provider stops on its own redirect error page) or the user is not assigned to the sign-in client. A sign-in as a different account is recorded as approver_identity_mismatch; the user sees Use a different account, and nothing is granted. While Alter is being upgraded, an OAuth request created by the previous version skips the already-connected shortcut and sends the user through the provider’s own sign-in instead; if the page’s sign-in start refuses such a request, session_outdated is shown to the user only — it never reaches the application or an SDK — and the user starts again from the application.
Sign-in clients added after the provider locked
Section titled “Sign-in clients added after the provider locked”The accepted token audiences lock with the provider’s first user (Audience binding). Adding a sign-in client to a locked provider that already has an explicit Audience would change that set, so Alter stores the client for approving delegations only: the approval sign-in verifies ID tokens against it, but tokens issued to that Client ID are not accepted as user tokens. Wallet sign-in and app.authenticate() refuse such a client with idp_signin_client_approvals_only (HTTP 409). The provider card shows the client’s scope — sign-in or approvals only — and the identity-provider response reports it in wallet_client_scope (sign_in, approvals_only, or null when there is no sign-in client). To sign users in with the same client, configure it before the provider’s first user is resolved.
Supported providers
Section titled “Supported providers”| Provider | Path |
|---|---|
| Auth0, Clerk, Okta, WorkOS | First-class — pick the tab below. |
| Other standards-compliant OIDC providers (OneLogin, Ping, Stytch, JumpCloud, …) | Use Custom OIDC — supply issuer, JWKS, audience, claim mappings. |
| Keycloak, Microsoft Entra ID, Amazon Cognito, Google, Firebase Auth, Supabase Auth | Broker through Auth0, Clerk, Okta, or WorkOS. Direct integration is rejected at validation time. |
How directory sync works
Section titled “How directory sync works”Without directory sync, Alter learns about a user the first time that user’s JWT arrives (just-in-time provisioning). Directory sync mirrors the IDP’s entire directory ahead of time — users and groups exist in Alter before anyone signs in, group-bound grants become assignable to people who haven’t authenticated yet, and users who will never send another JWT still get offboarded.
Webhooks and directory sync are complementary, not alternatives:
| Webhooks | Directory sync | |
|---|---|---|
| Latency | Real-time, per event | Scheduled — every 6 hours, plus on-demand |
| Coverage | Only events the IDP emits after setup | The full directory, including pre-existing users |
| Offboarding | Immediate on a delete/deactivate event | Users absent from the directory are deprovisioned on the next sync |
| Credential | Webhook signing secret | Management-API credential (read-only) |
Directory sync needs a management credential — a read-only credential for the IDP’s management API, created in the IDP’s own console and pasted into the app’s Identity page → the provider card → Directory Import (a per-provider walkthrough is shown inline). The credential is verified against the management API at save time: a definitive rejection (wrong secret, invalid host) returns a structured validation error and stores nothing; a transient provider failure saves the credential with a notice to check the first import’s status; provider-specific probes can also report partial verification (see the Auth0 tab). Once saved, trigger the first import with Run directory import; Alter then re-imports the full directory every 6 hours. Each run’s outcome (counts, last error) is visible in the same portal section, and every imported, updated, or deprovisioned user lands in the provisioning audit trail.
What groups can do
Section titled “What groups can do”What each provider supports:
| Provider | Users synced | Groups synced | Group grants | Group policies |
|---|---|---|---|---|
| Okta | Yes | Yes — Okta groups + memberships | Yes — requires Group claim emits stable group IDs on the IDP config | Yes |
| Clerk | Yes | Yes — Clerk organizations + memberships | Yes | Yes |
| WorkOS | Yes — AuthKit users | Yes — WorkOS organizations + active memberships | Yes — requires Group claim emits stable group IDs on the IDP config | Yes |
| Auth0 | Yes | Yes — Auth0 Groups + memberships (directory visibility) | Not supported — Auth0 group principals are not enabled for grants | Yes — groups from the sign-in group claim or directory sync |
| Custom OIDC | Not available | Not available — OIDC defines no management API | Not available | Yes — groups from the sign-in group claim |
Every synced group appears on the app’s Groups page — name, source, member count, and how many grants it backs. Groups are managed in the identity provider; the portal shows what synced and does not create groups.
A group policy restricts what every active member of one group may do through the application, whichever connection or agent they use (see Restrict one user or one group). Author it from the group’s Policies tab, the Create a restriction panel, alter policy rules create --group <group-id>, or a policy file. Unlike a group grant, a group policy that restricts does not need group webhooks: a grant that outlives a missed removal would leave access in place, but a restriction that outlives one only over-restricts a former member, and a new member is restricted from the sign-in that records their groups. The residual: a member removed at the provider keeps the restriction until the provider’s webhook, the next directory import, or the member’s next sign-in reports it; a member who never signs in again keeps a stale restriction on a provider without webhooks or directory sync. A group whose claim carries display names rather than stable ids is keyed by that name, so renaming it at the provider starts a new group without the old group’s policies. When the provider’s group-deleted webhook or deleting the identity provider removes a group, the group’s attachments and exclusions on other policies are removed, and a policy set on the group moves to one of the other places it is attached to (it is deleted only when it applies nowhere else); each of these changes is recorded in the audit log. Deleting the application deletes all of its policies, recorded as a single count on the application-deletion audit entry.
A group exclusion is the opposite case. Exempting a group from a wider rule is an access the member keeps until Alter learns they left, so it needs exactly what a group grant needs: Clerk, Okta or WorkOS with webhooks enabled. On any other setup the exclusion is refused with the reason. Disabling the provider’s webhooks is refused while such exclusions exist unless you force it, which removes them (each removal is recorded in the audit log).
Deprovisioning a user keeps the restrictions on them. A deprovisioned user loses their groups and connections, but the policies on their account (their own personal limits and the application’s restrictions) and their attachments and exclusions on other policies stay in place, and apply again if the user is re-provisioned. New policies, attachments, or exclusions on a deprovisioned user are refused: the portal and the CLI report the user as not found, and a policy file is refused at plan time with the reason.
Setup by provider
Section titled “Setup by provider”1. JWT verification
Section titled “1. JWT verification”In the Auth0 Dashboard, pick the API or application whose JWTs Alter should accept and note the Issuer URL and Audience. Issuers vary by tenant region — https://<tenant>.us.auth0.com/ (US — default for new tenants; other regions use eu, au, jp, ca, or uk), https://<tenant>.auth0.com/ (legacy, no region prefix), or the tenant’s custom-domain URL when one is configured.
In the Alter portal → app’s Identity page:
- Add Identity Provider → paste the issuer URL → Discover. Auth0 is recognized; claim mappings pre-fill.
- Enter the audience per the table above. If no matching API is registered yet, create one: Applications → APIs → Create API, Identifier = exactly the audience you paste here, signing algorithm RS256 — otherwise every sign-in fails at authorize with
Service not found: <audience>. - Skip group claims — group grants are not supported on Auth0 (use Okta, WorkOS, or Clerk if you need them). Group memberships still sync for directory visibility via step 4.
- Add Provider.
2. OIDC sign-in (required to sign users in and to approve delegations)
Section titled “2. OIDC sign-in (required to sign users in and to approve delegations)”Required for app.authenticate(), Wallet sign-in, and approving Connect delegations.
In Auth0: Applications → Create Application → Regular Web Application. Paste the SDK and Wallet callback URLs into Allowed Callback URLs (comma-separated) and the Wallet logout URL (bare URL, no query params) into Allowed Logout URLs. Copy the Client ID and Client Secret. Two Auth0-specific requirements:
- Authorize the application for the audience API (step 1’s API): open it under Applications → APIs and grant this application user-delegated access — the Application Access tab, or set the API’s User-delegated Access policy to allow all applications. Without this, sign-ins fail with
client is not authorized to access resource server. - RS256 ID tokens: confirm under Settings → Advanced Settings → OAuth → JSON Web Token (JWT) Signature Algorithm. New applications default to RS256; HS256 fails verification, because Alter validates ID tokens against the tenant’s public JWKS and accepts only asymmetric algorithms.
In Alter: User Authentication (OIDC) section → paste the credentials → Save.
3. Webhook deprovisioning (optional)
Section titled “3. Webhook deprovisioning (optional)”Alter consumes Auth0 user lifecycle events through a Log Stream. In Alter: Webhooks → Enable → copy the signing secret and endpoint URL (shown once).
In Auth0: Monitoring → Streams → Create Stream → Custom Webhook. Payload URL = the Alter endpoint; Authorization Token = the signing secret (no Bearer prefix — Auth0 adds it); Content Type = application/json; Content Format = JSON Object. Filter by Event and subscribe only to these codes: sdu (Success User Deletion → deprovision) and ublkdu (anomaly-detection login block released → reactivates a previously-suspended user). Do not subscribe to sul — it fires on every successful login and would flood the receiver. Auth0 publishes no log code for “admin manually blocked user”, so suspension is not auto-synced from Auth0; deprovisioning is reliable for explicit user deletes.
Alter accepts object, array and JSON-lines Log Stream deliveries, including
Auth0’s {"log_id":"…","data":{…}} wrapper. It also accepts tenant logs
in a com.auth0.Log CloudEvent. The nested log’s user_id identifies the
deleted subject; email is never a deletion lookup key. The log ID is kept
for duplicate suppression. A successful delivery acknowledgement is separate
from the per-user lifecycle result: verify the user.deleted provisioning
event and the user’s deprovisioned status when checking revocation.
Tenants with Auth0 Events API group-event delivery can optionally point an Event Stream at the same Alter endpoint and subscribe only to user.deleted, group.deleted, and group.member.deleted — these keep directory visibility current (the app’s Groups page reflects them on the next read) but do not enable Auth0 group-bound grants.
4. Directory sync (optional)
Section titled “4. Directory sync (optional)”Syncs users, Auth0 Groups (grp_…), and group memberships. Blocked Auth0 users sync as suspended; deleted users are deprovisioned on the next run.
In Auth0: Applications → Create Application → Machine to Machine Applications → authorize the new application for the Auth0 Management API with the read:users, read:groups, and read:group_members permissions → copy the tenant Domain, Client ID, and Client Secret from its Settings tab.
In Alter: the provider card → Directory Import → paste all three → Save credential → Run directory import.
Common pitfalls
Section titled “Common pitfalls”- Custom domain mismatch — JWTs use the custom domain but the portal has the tenant URL (or vice versa). Match exactly what’s in the JWT
issclaim. - Expecting group grants — not supported on Auth0; use Okta, WorkOS, or Clerk.
- Wrong Management API permission — grant the permissions under the application’s APIs tab for the Auth0 Management API, not on a different API. A credential without
read:usersis rejected at save time; missing group permissions save with a notice (above).
1. JWT verification
Section titled “1. JWT verification”The issuer is the Clerk instance URL: https://<app>.clerk.accounts.dev (development) or https://clerk.<custom-domain> (production).
In the Alter portal → Identity → Add Identity Provider → paste the issuer → Discover. Clerk is recognized; the user-ID claim pre-fills (sub = Clerk user ID). Leave Audience blank unless the app sends Alter tokens minted by a Clerk JWT template with a custom aud (see the table above).
For group grants (groups = Clerk organizations): the group claim must carry the active organization’s ID (org_…) — the same ID Clerk’s organization webhooks carry, so login and webhook resolve the same group. Clerk’s default v2 session token nests organization data under o (o.id, o.rol), which is not a top-level claim path, so configure a Clerk JWT template (Clerk Dashboard → JWT Templates) emitting it as a top-level claim — e.g. "groups": "{{org.id}}" — and enter that claim name in the Group Claim field before the first sign-in. Add Provider.
2. OIDC sign-in (required to sign users in and to approve delegations)
Section titled “2. OIDC sign-in (required to sign users in and to approve delegations)”Clerk OAuth applications support development and production instances; use credentials and the issuer from the same instance. See Clerk’s OAuth implementation. In Clerk: OAuth applications → Add OAuth application → select scopes openid, profile, and email → add the SDK and Wallet callback URLs. Copy the Client Secret from the modal immediately (Clerk cannot show it again) and the Client ID from the application’s settings page. Paste both into the Alter portal.
3. Webhook deprovisioning (optional)
Section titled “3. Webhook deprovisioning (optional)”In Alter: note the Webhook URL — do not click Enable yet. In Clerk: Webhooks → Add Endpoint → paste the Alter URL, then subscribe to exactly these four events (others are ignored by the receiver and only add delivery noise):
| Clerk event | What Alter does with it |
|---|---|
user.deleted | Deprovisions the user and revokes their grants |
user.updated | Keeps the user’s email / display name in sync |
organizationMembership.deleted | Revokes group-grant access the moment a member leaves an organization |
organization.deleted | Handles a deleted organization (group) — revokes its group grants |
Copy the Signing Secret (whsec_...). Back in Alter: toggle Enable Webhooks → paste the secret → Save.
4. Directory sync (optional)
Section titled “4. Directory sync (optional)”Syncs users, organizations (as groups), and organization memberships. Banned Clerk users sync as suspended; deleted users are deprovisioned on the next run.
In Clerk: Configure → API keys → copy the Secret key (sk_live_… on production instances, sk_test_… in development). In Alter: the provider card → Directory Import → paste it → Save credential → Run directory import.
Common pitfalls
Section titled “Common pitfalls”- Dev vs production instance — sign-in works with either. Issuers, OAuth applications, callback registrations, and secrets belong to their instance; do not mix development and production values.
- Custom JWT template — ensure
substill carries the user ID; override the user-ID claim mapping before the first sign-in if needed. - Publishable vs secret key — directory sync needs the Secret key (
sk_…), not the publishable key (pk_…), which is rejected at save time.
1. JWT verification
Section titled “1. JWT verification”In the Okta Admin Console → Security → API → Authorization Servers → pick the server (usually default) and note its Issuer URI and Audience. The host varies by tenant: https://<org>.okta.com/oauth2/default (standard production), https://<org>.okta-emea.com/oauth2/default (EMEA), https://<org>.oktapreview.com/oauth2/default (preview/dev), https://<org>.okta-gov.com/oauth2/default (FedRAMP), or https://<org>.okta.mil/oauth2/default (DoD IL4).
These are custom authorization server issuers (the /oauth2/<id> path — default is provided in Integrator Free Plan orgs and with API Access Management; confirm that the server and an access policy exist in your org), and a custom server is the recommended path. The org authorization server (issuer = the bare org URL, e.g. https://<org>.okta.com, no /oauth2/... path) has no Claims editor and no configurable audience — if you must use it, leave the Audience blank and configure Wallet sign-in (step 2) so the Client ID becomes the accepted audience.
Group claim. For membership visibility only: edit the authorization server → Claims → add a claim named groups, include in Access Token, value type Groups, filter Matches regex .* — this emits group names.
For group grants the claim must instead carry stable group IDs (00g…) in the ID token — IDs are what Okta’s group webhooks carry, so a name-keyed claim would never match and revocation would silently no-op (Alter rejects group grants on an Okta IDP without stable-ID keying). Pick the path matching your issuer:
- Custom authorization server: Claims → add/edit the
groupsclaim → include in ID Token, value type Expression, valuegetFilteredGroups({"00g…"}, "group.id", 40)(static allow-list) oruser.getGroups({'group.type': {'OKTA_GROUP'}}).. Then Scopes → Add Scope → namegroups, and confirm the server’s Access Policies grant it — custom servers don’t include the scope by default. - Org authorization server: no Claims editor — configure the claim on the OIDC app instead: the app’s Sign On tab → OpenID Connect ID Token → Group claims (type Expression, same value as above). The
groupsscope is built-in on the org server.
In the Alter portal → Identity → Add Identity Provider → paste the issuer URI → Discover. Okta is recognized; the user-ID claim pre-fills (sub, which is the Okta user ID in ID tokens; access tokens from a custom authorization server carry the user’s login in sub and the user ID in uid, which is how an access-token session is matched to the user’s approval sign-in). Set the Audience per the table above, map the group claim, and tick Group claim emits stable group IDs if using group grants — all before the first sign-in. Add Provider.
2. OIDC sign-in (required to sign users in and to approve delegations)
Section titled “2. OIDC sign-in (required to sign users in and to approve delegations)”In Okta: Applications → Create App Integration → OIDC → Web Application. Sign-in redirect URIs = the SDK and Wallet callback URLs; Sign-out redirect URIs = the Wallet logout URL. Assign the app to the groups whose users should be able to sign into Alter Wallet or approve Connect delegations. Copy the Client ID and Client Secret into the Alter portal.
3. Webhook deprovisioning (optional)
Section titled “3. Webhook deprovisioning (optional)”Okta owns secret generation: you set the Event Hook secret in the Okta Admin Console, then paste the same value into Alter — clicking Enable in Alter opens a paste dialog expecting the value Okta has. In Alter: note the Webhook URL first; do not click Enable yet.
In Okta: Workflow → Event Hooks → Create Event Hook. URL = the Alter webhook URL; Authentication field = Authorization; set the secret to a value you control and copy it — Okta does not retrieve it for you later. Subscribe to these events:
| Okta event | What Alter does with it |
|---|---|
user.lifecycle.delete.initiated | Deprovisions the user and revokes their grants |
user.lifecycle.deactivate | Deprovisions the user and revokes their grants |
user.lifecycle.suspend | Suspends the user |
user.lifecycle.unsuspend, user.lifecycle.reactivate, user.lifecycle.activate | Restore a previously-suspended user to active |
group.user_membership.remove | Revokes group-grant access the moment a member is removed from a group |
group.lifecycle.delete | Handles a deleted group — revokes its group grants |
Verify and Activate the Event Hook — Okta sends a GET challenge to the Alter URL automatically. Allow a few minutes after verification before relying on the hook: Okta does not deliver events that occur in the first minutes after a hook is verified, and they are not retried. Back in Alter: toggle Enable Webhooks → paste the same secret value → Save.
4. Directory sync (optional)
Section titled “4. Directory sync (optional)”Syncs users, Okta groups, and group memberships — including users in DEPROVISIONED state, so offboarding done in Okta is mirrored. Suspended Okta users sync as suspended; deactivated (DEPROVISIONED) users are deprovisioned in Alter.
In Okta:
- Applications → Create App Integration → API Services.
- In the new app: General → Client Credentials → Edit → set Client authentication to Public key / Private key → Add key → Generate new key → copy the private key in JWK (JSON) format (Okta shows it only once).
- Okta API Scopes tab → grant
okta.users.readandokta.groups.read. - Admin roles tab → assign the Read-only Administrator role — Okta rejects management-API calls from API service apps that hold no admin role.
In Alter: the provider card → Directory Import → paste the Org URL (https://<org>.okta.com), the app’s Client ID, and the private key JWK → Save credential → Run directory import. The Key ID (kid) field is only needed when the pasted JWK omits its own kid.
Common pitfalls
Section titled “Common pitfalls”- Custom Authorization Server — the issuer URI is
https://<org>.okta.com/oauth2/<server-id>, not the org URL. - Missing group claim — Okta emits no groups by default; without the claim, group memberships are not recorded and group-bound grants don’t work.
- Group claim emits names, not IDs — group grants require stable group IDs plus the Group claim emits stable group IDs setting (step 1). A name-emitting claim still records memberships but cannot back a group grant.
groupsscope missing on a custom authorization server — sign-in works fine, yet group-bound grants match nobody, because Alter requests only advertised scopes. Add the scope (step 1); the org server has it built-in.- Group claim emitted only on the Access Token — for group grants the claim must be in the ID token. The org server’s access token is opaque and can’t carry it; on a custom server, set the Expression claim to include the ID Token.
- Audience mismatch — a custom authorization server’s default audience is
api://default; JWTs with a differentaudfail verification.api://defaultnever applies to the org server — its tokens carry the OIDC Client ID, so settingapi://defaultthere fails every verification. - Missing admin role on the API service app — token exchange succeeds but every directory read returns 403, so the credential is rejected at save time. Assign Read-only Administrator to the app itself, not to a user.
- Public key pasted instead of private — the JWK must contain the private parts (
d,p,q, …); the public half cannot sign the client assertion and is rejected at save time.
WorkOS exposes two issuers per environment, and picking the right one matters:
- Connect issuer —
https://<slug>.authkit.app(the environment’s AuthKit domain). A standards-compliant OIDC authorization server that issuesid_tokens. Use this issuer — it supports every layer below, including OIDC sign-in. - Native AuthKit issuer —
https://api.workos.com/user_management/<client_id>. Verifies AuthKit access tokens, but its token endpoint returns noid_token, so OIDC sign-in (Wallet,app.authenticate(), and approving Connect delegations) does not work against it. Use it only for JWT verification of an app that already authenticates with AuthKit directly.
Both issuers publish OIDC discovery documents, and Alter resolves the JWKS URL from discovery automatically — the native issuer’s JWKS lives at https://api.workos.com/sso/jwks/<client_id>, not under the issuer path, which is why manual JWKS guesses fail and discovery is the supported path. A custom auth domain changes the issuer to the organization’s own domain, which is detected as Custom OIDC.
1. JWT verification
Section titled “1. JWT verification”In the WorkOS Dashboard → Connect → Applications (the Connect item in the sidebar’s Products section — not the top-level Applications page, which manages the native AuthKit application) → create or open the Connect application.
The issuer is the environment’s AuthKit domain, found under Domains (Developer section) → AuthKit — it is not displayed on the Connect application page. WorkOS shows only the bare domain without a scheme (for example youthful-ginger-43.authkit.app; staging environments use an auto-generated phrase) — paste it exactly as shown and the portal prepends the https:// scheme for you (typing the full URL also works). To verify, open https://<domain>/.well-known/openid-configuration in a browser — its issuer field must match the stored issuer exactly.
In the Alter portal → Identity → Add Identity Provider → paste the issuer → Discover. WorkOS is recognized; the user-ID claim pre-fills (sub = the AuthKit user ID, user_…). For Audience, copy the actual aud of the Connect user access token your app sends to Alter: the requested resource indicator (your API/MCP server URL), or the environment’s Client ID (client_…, from API Keys) when no resource is requested. See WorkOS’s access-token claims. Do not substitute the environment Client ID for a resource audience. The separate Connect application’s Client ID is the ID-token audience and belongs in the OIDC sign-in section below. Configure the expected access-token audience before first use; a mismatch rejects the token, including its org_id group membership.
For group grants (groups = WorkOS organizations): enter org_id in the Group Claim field and tick Group claim emits stable group IDs. WorkOS access tokens carry the active organization’s stable ID (org_…) in the org_id claim — the same ID its organization_membership.* webhooks carry. The claim is a single value (one active organization per session), which Alter handles. Configure this before the first sign-in. Add Provider.
2. OIDC sign-in (required to sign users in and to approve delegations)
Section titled “2. OIDC sign-in (required to sign users in and to approve delegations)”Requires the Connect issuer (above). In WorkOS: Connect → Applications → open the application → add the SDK and Wallet callback URLs to Redirect URIs. Copy the Client ID and Client Secret from the creation dialog — the secret is displayed only at creation, and only when “Use PKCE” was left unchecked. A PKCE (public) application is never issued a client secret and the setting cannot be changed afterwards — recreate the application without PKCE. (Alter sends a PKCE code challenge on every sign-in regardless; the unchecked box only means a client secret exists too.)
If the secret was not saved at creation, the dashboard has no re-mint UI — create a new secret with the WorkOS API, using the environment’s secret API key (sk_…, from the API Keys page) and the application’s app_… ID:
curl -X POST "https://api.workos.com/connect/applications/<app_id>/client_secrets" \ --header "Authorization: Bearer <sk_api_key>"The response’s secret field is returned only this once — store it immediately. Paste the Client ID and Client Secret into the Alter portal.
WorkOS has no RP-initiated logout endpoint, so there is no Wallet logout URL to register — signing out of the Wallet ends the Alter session only.
3. Webhook deprovisioning (optional)
Section titled “3. Webhook deprovisioning (optional)”WorkOS issues the signing secret when the webhook endpoint is created. In Alter: note the Webhook URL; do not click Enable yet. In WorkOS: Webhooks → Create Webhook → Endpoint URL = the Alter URL. Subscribe to exactly these events:
| WorkOS event | What Alter does with it |
|---|---|
user.deleted | Deprovisions the user and revokes their grants |
user.updated | Keeps the user’s email / display name in sync |
organization_membership.deleted | Revokes group-grant access the moment a member leaves an organization |
organization_membership.updated | Handles membership deactivation (the event’s status becomes inactive) — treated as a removal; other status changes are ignored |
organization.deleted | Revokes every grant bound to the organization’s group, then removes the group |
Copy the webhook’s Signing Secret. Back in Alter: toggle Enable Webhooks → paste the secret → Save.
4. Directory sync (optional)
Section titled “4. Directory sync (optional)”Syncs AuthKit users, WorkOS organizations (as groups), and active organization memberships — inactive/pending memberships are not imported, because they must not confer group access. AuthKit users have no suspended state; users deleted in WorkOS are deprovisioned on the next run.
In WorkOS: API Keys → copy the environment’s secret API key (sk_…; production keys are shown once at creation — regenerate if it was not saved). In Alter: the provider card → Directory Import → paste it → Save credential → Run directory import.
Common pitfalls
Section titled “Common pitfalls”- Native issuer used for sign-in —
https://api.workos.com/user_management/<client_id>verifies access tokens but returns noid_token, so Wallet /app.authenticate()sign-in fails against it and users cannot approve Connect delegations (managed-secret delegation requests fail withidp_signin_not_configured, reasonissuer_cannot_sign_in). Use the Connect issuer (https://<slug>.authkit.app). - Guessing the JWKS URL — the native issuer’s JWKS is not at
<issuer>/.well-known/jwks.json. Alter’s OIDC discovery resolves it correctly; hand-configured JWKS URLs are the thing that breaks. - Group claim not set to
org_id— WorkOS pre-fills no group claim. Withoutorg_idplus Group claim emits stable group IDs, organization memberships are not recorded and group grants cannot be created. - “Use PKCE” checked on the Connect application — a PKCE application is never issued a client secret, and WorkOS rejects API secret-minting with
Cannot create client secrets for applications that use PKCE. Recreate the application with the checkbox unchecked. - Organization has no active members — an import showing the group but a synced-user count of 0 usually means no active members: an un-accepted (
pending) invitation is not imported. Add the member in Organizations → (org) → Members and re-run. On repeat runs, unchanged counts are healthy idempotence, not a failure. - Custom auth domain — a CNAME’d AuthKit domain changes the issuer to the custom domain, detected as Custom OIDC (webhooks / directory sync then unavailable). Use the
authkit.appissuer for first-class support.
For any OIDC-compliant provider not listed above (OneLogin, Ping, Stytch, JumpCloud, etc.). Providers in the brokered-only row of the support table — Keycloak, Microsoft Entra ID, Amazon Cognito, Google, Firebase Auth, Supabase Auth — are rejected at validation time and must be brokered through Auth0, Clerk, Okta, or WorkOS using the broker’s enterprise-connection feature.
1. JWT verification
Section titled “1. JWT verification”From the provider’s documentation, find the Issuer URL (the iss claim), JWKS URL (usually <issuer>/.well-known/jwks.json), Audience (the aud claim), user-ID claim (default sub), and group claim (provider-specific — common values: groups, cognito:groups, roles).
In the Alter portal → Identity → Add Identity Provider → paste the issuer URL → Discover. When OIDC discovery is exposed at <issuer>/.well-known/openid-configuration, Alter pulls the JWKS automatically. Paste the exact token Audience — or, if the provider validates the audience against its own registered list and gives you no way to register one, leave it blank so the Wallet Client ID becomes the accepted audience (see Clearing the audience). Override claim mappings when the JWT uses non-standard names — before any user signs in (they lock after first authentication).
2. OIDC sign-in (required to sign users in and to approve delegations)
Section titled “2. OIDC sign-in (required to sign users in and to approve delegations)”Create an OIDC application (often called “Web App” or “Confidential Client”) at the provider. Add the SDK and Wallet callback URLs as callbacks; when the provider supports post_logout_redirect_uri, add the Wallet logout URL. Paste the Client ID and Client Secret into the Alter portal.
3. Webhook deprovisioning (optional)
Section titled “3. Webhook deprovisioning (optional)”In Alter: Webhooks → Enable → copy the secret and endpoint. In the IDP, configure a webhook subscribing to user-deleted / user-disabled events with the secret as an Authorization header. When the IDP supports no webhooks, deprovisioning waits until the deleted user’s JWT expires.
4. Directory sync
Section titled “4. Directory sync”Not available — OIDC standardizes authentication, not a management API, so there is no directory to read. Users are provisioned just-in-time on first sign-in; offboarding relies on webhooks (when the provider has them) or JWT expiry.
Common pitfalls
Section titled “Common pitfalls”- Brokered-only providers fail at save time. Issuer URLs from Keycloak, Entra, Cognito, Google (
accounts.google.com), Firebase, or Supabase are rejected — use the broker pattern instead. - Audience formatting — some providers send a string, some an array. Alter accepts a string or a single-element array matching a configured value; arrays listing additional recipients are rejected, except the issuer’s own
/userinfoendpoint alongside an accepted value.
Deleting an identity provider
Section titled “Deleting an identity provider”Deleting a provider with active users uses Force delete: Alter marks the provider as deleting, deprovisions users and revokes their grants, removes the provider’s groups (moving or deleting the group policies as described in What groups can do), then removes the configuration and Vault references. The policies on the deprovisioned users stay. While the marker exists, sign-ins, directory mutations, webhook changes, and configuration edits are blocked.
If a provider or Vault failure interrupts the cascade, the card remains visible as Deleting. Use Resume force delete after correcting the underlying failure — the cascade is idempotent and continues from the remaining active users.