# Identity Provider Setup Guide

This guide explains how to connect an Identity Provider (IdP) to Open Access SSO so
your users can log in to WordPress with their existing organizational accounts.

Open Access SSO is a **SAML 2.0 Service Provider** and an **OpenID Connect Relying
Party**. It works with any standards-compliant SAML 2.0 IdP or OpenID Connect provider
(OP). This guide gives concrete steps for the most common providers — Microsoft Entra ID
(Azure AD), Okta, NetIQ Access Manager (now OpenText), and Keycloak, each of which
supports both protocols — followed by a generic fallback for each protocol that applies
to every other provider (Google Workspace, OneLogin, Auth0, ADFS, Shibboleth,
SimpleSAMLphp, PingFederate, and so on).

**Choosing a protocol.** If a provider supports both, either works; OpenID Connect is
generally simpler to register (no XML metadata exchange, no certificates to paste) and
is the newer of the two, while SAML remains the safer default for providers with mature
enterprise SSO tooling built around it. Whichever you pick, **the protocol is chosen when
you create the IdP in the plugin and cannot be changed afterwards** — the two protocols
store different fields and key user identity differently, so switching midstream isn't a
form of "edit," it's a different provider. To switch protocol for a provider you've
already connected, delete it and add it again with the same real-world provider on the
other protocol.

---

## The general flow

Connecting any IdP follows the same five steps, whether it speaks SAML or OpenID
Connect. The provider-side wording differs from product to product, but the data you
exchange is always the same shape.

1. **Add the IdP in the plugin.** In WordPress admin, go to
   **Open Access SSO → Identity Providers → Add New**, and choose a protocol. For SAML,
   you can either import the IdP's metadata (XML file or URL) to auto-fill most fields,
   or enter them by hand. For OpenID Connect, you can run **discovery** against the
   provider's issuer URL to auto-fill its endpoints, or enter them by hand.
2. **Give the provider your SP/RP details.** For SAML, open the **Service Provider** tab
   and copy the Entity ID, ACS URL, SLO URL, and/or the full SP metadata XML. For OpenID
   Connect, copy the **Redirect URI** and **post-logout redirect URI** shown on the IdP
   edit screen. Register these at the provider as a new application / trust / client.
3. **Bring the provider's details back into the plugin.** For SAML, copy the IdP's
   Entity ID, Sign-On URL, Logout URL, and signing certificate into the IdP record (or
   let metadata import fill them). For OpenID Connect, copy the **Client ID** and
   **Client Secret** the provider issues you (or let discovery fill in the endpoints).
4. **Map attributes/claims and roles.** Tell the plugin which SAML attributes (or OIDC
   claims) carry the user's email, name, and group membership, and (optionally) how
   groups map to WordPress roles.
5. **Test.** Use the per-IdP **Test Connection** button on the Identity Providers list to
   run a real login round-trip — for SAML or OpenID Connect alike — before turning SSO on
   for everyone.

---

## Your Service Provider (SP) details

These are the values the IdP needs in order to trust your site. You will find all of
them on the **Open Access SSO → Service Provider** tab, each with a copy button, plus a
full **Metadata XML** box you can paste straight into an IdP that accepts SP metadata.

| What the IdP calls it | Value in Open Access SSO |
|---|---|
| **Entity ID** / Audience URI / SP Identifier | `https://your-site.example/` (your site's home URL with a trailing slash) |
| **ACS URL** / Reply URL / Assertion Consumer Service | `https://your-site.example/?oasso_acs=1` |
| **SLO URL** / Logout URL / Single Logout Service | `https://your-site.example/?oasso_slo=1` |

Notes:

- The **Entity ID is your site home URL**, e.g. `https://example.com/`. It is shown
  read-only on the Service Provider tab — you do not type it in.
- The **ACS endpoint** receives the SAML Response after login. It is the query string
  `?oasso_acs=1` on your home URL; there is no separate path or page.
- The **SLO endpoint** handles both IdP-initiated logout and the response to an
  SP-initiated logout. It is `?oasso_slo=1` on your home URL.
- There is **no separate metadata download URL** — the SP metadata is the XML in the
  textarea on the Service Provider tab. Copy it from there.

### SP signing and encryption keys (optional, but required by some IdPs)

Some IdPs require the SP to **sign its login requests**, and some **encrypt their
assertions**. Both need an SP key pair. On the **Service Provider** tab:

- Paste an **SP Certificate (X.509)** and the matching **SP Private Key** (PEM format).
  The plugin verifies the pair matches and stores the private key **encrypted at rest**.
- Tick **Sign Outgoing Requests** if the IdP requires signed AuthnRequests. This is
  reflected as `AuthnRequestsSigned="true"` in your SP metadata.
- For encrypted assertions, the same key pair is used to decrypt by default. You may
  optionally supply a **separate** SP Encryption Certificate and Encryption Private Key.

When an SP certificate is set, the SP metadata advertises both signing and encryption
key descriptors and the algorithms the plugin accepts (RSA-OAEP key transport, and
AES-128/256 in GCM and CBC modes). Assertions are always required to be signed
(`WantAssertionsSigned="true"`).

### Security defaults worth knowing before you start

These are on by default and you usually should keep them on. If a specific IdP fails
during testing with an audience or expiry error, the Service Provider tab lets you
relax them per the on-screen guidance:

- **Require Audience Restriction** — the assertion must name your SP Entity ID as its
  audience.
- **Require Assertion Expiry** — the assertion must carry an expiry timestamp.
- Signatures must use RSA-SHA256/384/512 (SHA-1 is rejected). Encrypted assertions must
  use RSA-OAEP key transport with AES-CBC/GCM data encryption.

---

## Your OpenID Connect (RP) details

If you are connecting a provider as OpenID Connect instead of SAML, register these two
URLs at the provider when you create the client/application. Both are shown, with copy
buttons, on the **Identity Providers → edit** screen once you choose the OpenID Connect
protocol — you do not need to construct them by hand.

| What the provider calls it | Value in Open Access SSO |
|---|---|
| **Redirect URI** / Callback URL | `https://your-site.example/?oasso_oidc_cb=1` |
| **Post-logout redirect URI** / Sign-out redirect URI | `https://your-site.example/` (your site's home URL) |

Notes:

- The **Redirect URI is the same for every OpenID Connect provider on your site** — it
  does not vary per IdP — so it is worth copying before you have even finished creating
  the client at the provider; some providers require it at registration time, before
  they will issue a Client ID.
- Register both values **exactly as shown**. Providers match them byte-for-byte,
  including scheme, port, and trailing characters — a mismatch on either one is one of
  the most common OpenID Connect setup failures (see
  [Troubleshooting](troubleshooting.md#4-redirect_uri-mismatch)).
- Your site must be served over **HTTPS**. The plugin requires HTTPS for every OpenID
  Connect endpoint it talks to (authorization, token, UserInfo, JWKS, discovery, and
  end-session) — there is no setting to relax this on a live site.
- Open Access SSO uses the **authorization code flow with PKCE (S256 only)**. It never
  requests the implicit or hybrid flow, and never offers the `plain` PKCE method — if a
  provider's client-registration screen asks you to choose a flow or grant type, pick
  **Authorization Code** (sometimes labeled "Auth Code" or "Web application").
- **Protocol is chosen when you create the IdP and cannot be changed afterwards** (see
  above) — this applies to OpenID Connect exactly as it does to SAML.

---

## 1. Microsoft Entra ID (Azure AD)

**In Entra ID:**

1. Go to **Identity → Applications → Enterprise applications → New application →
   Create your own application**, choose **Integrate any other application
   (Non-gallery)**.
2. Open the app, then **Single sign-on → SAML**.
3. Under **Basic SAML Configuration**, set:
   - **Identifier (Entity ID)** = your SP Entity ID (`https://your-site.example/`)
   - **Reply URL (ACS)** = `https://your-site.example/?oasso_acs=1`
   - **Logout URL** = `https://your-site.example/?oasso_slo=1`
4. Under **SAML Certificates**, download the **Certificate (Base64)** — this is the IdP
   signing certificate.
5. From **Set up <app name>**, copy the **Login URL** (SSO URL), **Logout URL**, and
   **Microsoft Entra Identifier** (the IdP Entity ID). You can also copy the **App
   Federation Metadata Url** to import instead.
6. Assign users/groups to the app so they are allowed to sign in.

**Typical claims Entra ID emits** (these are the SAML attribute names you map in the
plugin — they are the plugin's built-in defaults, so a fresh IdP often needs no manual
attribute mapping):

- Email: `http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress`
- First name: `http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname`
- Last name: `http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname`
- Groups (if you add the optional groups claim): `http://schemas.microsoft.com/ws/2008/06/identity/claims/groups`

**In Open Access SSO:** Identity Providers → Add New. Either paste the **App Federation
Metadata Url** into **Metadata URL** and import, or enter Entity ID, SSO URL, SLO URL,
and the Base64 certificate manually. Entra ID uses the **HTTP-Redirect** binding for
SSO, which is the default.

**As OpenID Connect instead:**

1. Go to **Identity → Applications → App registrations → New registration**. Under
   **Redirect URI**, choose platform **Web** and paste
   `https://your-site.example/?oasso_oidc_cb=1`.
2. After registration, note the **Application (client) ID** and the **Directory
   (tenant) ID**. Under **Certificates & secrets**, create a **New client secret** and
   copy its value immediately — Entra shows it only once.
3. The **Issuer URL** for discovery is
   `https://login.microsoftonline.com/<tenant-id>/v2.0`.
4. If you need group membership for role mapping, add a `groups` claim via **Token
   configuration → Add groups claim**. Entra omits `groups` from the ID token once a
   user belongs to more than roughly 150 groups, so leave **Fetch the UserInfo
   endpoint** enabled in the plugin — it is the reliable way to get `groups` regardless
   of membership count.
5. Under **Authentication**, do not enable ID tokens/access tokens for implicit or
   hybrid flow — the plugin never requests either, and leaving them off matches what it
   actually uses (authorization code + PKCE).

**In Open Access SSO:** Identity Providers → Add New → **OpenID Connect**. Enter the
Issuer URL above and click **Fetch from discovery** to fill in the endpoints, then enter
the Client ID and Client Secret from step 2.

---

## 2. Okta

**In Okta (Admin Console):**

1. Go to **Applications → Applications → Create App Integration → SAML 2.0**.
2. On the **Configure SAML** step:
   - **Single sign-on URL** = `https://your-site.example/?oasso_acs=1` (leave "Use this
     for Recipient and Destination" checked).
   - **Audience URI (SP Entity ID)** = `https://your-site.example/`
   - Optionally set a **Single Logout** URL = `https://your-site.example/?oasso_slo=1`.
3. Add **Attribute Statements** for the values you want, for example:
   - `email` → `user.email`
   - `firstName` → `user.firstName`
   - `lastName` → `user.lastName`
   - And a **Group Attribute Statement** named `groups` if you want role mapping.
4. Finish the wizard, then on the app's **Sign On** tab open **View SAML setup
   instructions** (or **Identity Provider metadata**). From there copy the
   **Identity Provider Single Sign-On URL** (SSO URL), the **Identity Provider Issuer**
   (IdP Entity ID), and the **X.509 Certificate**. The metadata link can be imported
   directly.
5. Assign people/groups to the app.

**Typical attribute names Okta emits:** whatever you named them in the Attribute
Statements above — commonly `email`, `firstName`, `lastName`, and `groups`. Because Okta
uses short names rather than the Microsoft claim URIs, set up the matching rows on the
plugin's Attribute Mapping after connecting.

**In Open Access SSO:** Identity Providers → Add New. Import Okta's metadata URL, or
enter Entity ID / SSO URL / certificate manually. Okta defaults to the HTTP-Redirect
binding.

**As OpenID Connect instead:**

1. Go to **Applications → Applications → Create App Integration → OIDC – OpenID
   Connect**, application type **Web Application**.
2. Under **Sign-in redirect URIs**, add `https://your-site.example/?oasso_oidc_cb=1`.
   Under **Sign-out redirect URIs**, add `https://your-site.example/` (your site's home
   URL).
3. Assign the app to the people/groups who should be able to sign in, then save. Note
   the **Client ID** and **Client secret** from the app's **General** tab.
4. Your **Issuer URL** is your Okta domain, for example
   `https://your-org.okta.com` (or `https://your-org.okta.com/oauth2/<auth-server-id>`
   if you use a custom authorization server rather than the default `org` one).
5. Okta scopes `groups` to the UserInfo response by default, not the ID token, so leave
   **Fetch the UserInfo endpoint** enabled in the plugin if you plan to map roles from
   group membership. Add a **Groups claim filter** on the authorization server if you
   need it exposed at all.

**In Open Access SSO:** Identity Providers → Add New → **OpenID Connect**. Enter the
Issuer URL above, click **Fetch from discovery**, then enter the Client ID and Client
Secret from step 3.

---

## 3. NetIQ Access Manager (now OpenText)

> The SAML IdP is **NetIQ Access Manager** (now part of OpenText) — specifically its
> *Identity Server* component. *NetIQ Identity Manager (IDM)* is a separate provisioning
> product, **not** a SAML IdP; don't confuse the two.

NetIQ Access Manager deployments commonly require **signed AuthnRequests** and may **encrypt the
assertion**. Open Access SSO supports both, including RSA-OAEP key transport with a
**SHA-256** digest, which modern NetIQ Access Manager configurations use.

**Before you start, in Open Access SSO:** on the **Service Provider** tab, paste an SP
Certificate and SP Private Key, and tick **Sign Outgoing Requests**. If NetIQ encrypts
assertions, the same key pair decrypts them by default (or supply a separate encryption
cert/key). Copy your SP metadata XML from the same tab.

**In NetIQ:**

1. In the Administration Console, create a new **SAML 2.0 Service Provider** trust under
   the Identity Server cluster (Devices → Identity Servers → Edit → SAML 2.0 → New →
   Service Provider).
2. Import the SP by uploading the **SP metadata XML** you copied, or by entering the
   Entity ID (`https://your-site.example/`) and the ACS endpoint
   (`https://your-site.example/?oasso_acs=1`) manually.
3. Configure the trust to **require signed authentication requests** (this matches the
   plugin's signing). Confirm the SP signing certificate from your metadata is trusted.
4. If you want encrypted assertions, enable assertion encryption for this trust using
   the SP encryption certificate from your metadata; ensure the key transport is
   **RSA-OAEP** (SHA-256 is supported by the plugin) with an AES (CBC or GCM) data
   cipher.
5. Configure the attribute set the trust sends (see below), then export the **Identity
   Server / IdP metadata** (or note its metadata URL) so you can import it into the
   plugin. From it you will get the IdP Entity ID, SSO URL, SLO URL, and signing
   certificate.

**Typical attributes NetIQ emits:** these are configurable in the NetIQ attribute set.
LDAP-backed deployments often send `mail` (email), `givenName`, `sn` (surname), and a
group/role attribute such as `groupMembership` or a custom `roles` attribute. Map these
on the plugin's Attribute Mapping (and Role Mapping) after connecting.

**In Open Access SSO:** Identity Providers → Add New. Import the NetIQ Identity Server
metadata, or enter the values manually. Set the SSO/SLO bindings to match the NetIQ
trust (Redirect or POST).

**As OpenID Connect instead:**

NetIQ Access Manager's OAuth/OpenID Connect provider is a separate configuration path
from the SAML Identity Server trust above (typically under **OAuth and OpenID Connect →
Client Applications** in the Administration Console) — ask your NetIQ administrator to
register a new client there if you don't manage it yourself.

1. Register a new **confidential** OAuth/OIDC client. Set its **Redirect URI** to
   `https://your-site.example/?oasso_oidc_cb=1` and, if the field exists, its
   **Post Logout Redirect URI** to `https://your-site.example/`.
2. Grant it the **Authorization Code** grant type only. Do not enable Implicit or
   Hybrid — the plugin never requests them.
3. **Leave ID token encryption off** for this client. NetIQ's OIDC provider can
   optionally encrypt ID tokens (JWE) to the client's registered public key; this plugin
   is a secret-authenticated confidential client with no keypair of its own and does not
   support encrypted ID tokens. Leaving encryption unset — signed ID token only — is
   what the plugin expects. See
   [Troubleshooting: "client jwks is missing"](troubleshooting.md#1-client-jwks-is-missing-http-400-at-the-token-endpoint)
   if you hit this after the fact.
4. Note the **Client ID** and **Client Secret**, and the provider's **Issuer URL**
   (the discovery document is normally at
   `https://<netiq-host>/nidp/oauth/nam/.well-known/openid-configuration` or similar —
   confirm the exact path with your NetIQ administrator, since it can vary by
   deployment).
5. Attribute/claim names on NetIQ are rarely the defaults you'd guess — LDAP-backed
   deployments commonly send `mail` rather than `email`, plus attributes like `cn` and a
   `groups` claim. Don't hand-guess these: run **Test Connection** after saving the IdP
   (see [Verifying with Test Connection](#verifying-with-test-connection)) and read the
   exact claim names back from the result.
6. NetIQ's discovery document is not always a reliable guide to what it actually signs
   with — leave **ID token signature algorithm** set to its default ("Any supported
   algorithm") rather than pinning it to whatever discovery advertises. See
   [Troubleshooting](troubleshooting.md#2-the-providers-discovery-document-can-understate-what-it-actually-signs-with)
   for why.

**In Open Access SSO:** Identity Providers → Add New → **OpenID Connect**. Enter the
Issuer URL from step 4 and click **Fetch from discovery**, or enter the endpoints by
hand if discovery is not reachable from your WordPress server. Enter the Client ID and
Client Secret from step 4.

---

## 4. Keycloak

**In Keycloak (Admin Console):**

1. Select your realm, go to **Clients → Create client**, choose **Client type: SAML**.
2. Set **Client ID** = your SP Entity ID (`https://your-site.example/`). The Client ID
   is the SAML Entity ID Keycloak expects.
3. Save, then under the client's **Settings**:
   - **Valid redirect URIs** = `https://your-site.example/?oasso_acs=1`
   - **Master SAML Processing URL** (or the ACS line in **Fine Grain SAML Endpoint
     Configuration**) = `https://your-site.example/?oasso_acs=1`
   - Set the **Logout Service** (Redirect/POST) to `https://your-site.example/?oasso_slo=1`.
   - The simplest route is to import the SP metadata XML: on the client **import**
     option, upload the SP metadata from the plugin's Service Provider tab.
4. Under **Client scopes** / **Mappers**, add mappers so the assertion carries email,
   first name, last name, and group membership.
5. Get the IdP details: visit the realm's SAML metadata at
   `https://<keycloak-host>/realms/<realm>/protocol/saml/descriptor`. From it you get
   the IdP Entity ID (`https://<keycloak-host>/realms/<realm>`), the SSO/SLO endpoint
   (`.../protocol/saml`), and the realm signing certificate.

**Typical attribute names Keycloak emits:** whatever your mappers are named. Common
choices are `email`, `firstName` / `givenName`, `lastName` / `surname`, and a `roles` or
`groups` attribute. Configure the matching rows on the plugin's Attribute Mapping after
connecting.

**In Open Access SSO:** Identity Providers → Add New. Paste the realm descriptor URL
into **Metadata URL** and import, or enter Entity ID / SSO URL / certificate manually.

**As OpenID Connect instead:**

1. Select your realm, go to **Clients → Create client**, choose **Client type: OpenID
   Connect**. Set a **Client ID** (any identifier you choose — unlike SAML, it does not
   need to be your site's URL).
2. Enable **Client authentication** (makes it confidential, so a secret is issued) and
   the **Standard flow** (authorization code) only — leave **Direct access grants** and
   any implicit/hybrid options off.
3. Under **Settings**, set **Valid redirect URIs** to
   `https://your-site.example/?oasso_oidc_cb=1` and **Valid post logout redirect URIs**
   to `https://your-site.example/`.
4. On the **Credentials** tab, copy the **Client secret**.
5. Your **Issuer URL** for discovery is
   `https://<keycloak-host>/realms/<realm>` (the same base as the SAML entity ID above,
   without `/protocol/saml/descriptor`).
6. Under **Client scopes**, add a mapper for group membership (a `groups` claim) if you
   want role mapping — Keycloak does not include it by default.

**In Open Access SSO:** Identity Providers → Add New → **OpenID Connect**. Enter the
Issuer URL from step 5 and click **Fetch from discovery**, then enter the Client ID and
Client Secret from steps 1 and 4.

---

## 5. Generic SAML 2.0 IdP

Any SAML 2.0 IdP (Google Workspace, OneLogin, Auth0, ADFS, Shibboleth, SimpleSAMLphp,
PingFederate, and others) connects with the same exchange.

**Give the IdP these SP values** (from the Service Provider tab):

- **Entity ID / Audience** = `https://your-site.example/`
- **ACS / Reply URL** = `https://your-site.example/?oasso_acs=1`
- **Single Logout URL** = `https://your-site.example/?oasso_slo=1`
- If the IdP accepts SP metadata, paste the **Metadata XML** from the Service Provider
  tab instead of entering each field.
- If the IdP requires signed requests or encrypts assertions, configure the SP key pair
  and tick **Sign Outgoing Requests** as described in
  [SP signing and encryption keys](#sp-signing-and-encryption-keys-optional-but-required-by-some-idps).

**Collect these from the IdP and add them in Identity Providers → Add New:**

- **Entity ID** of the IdP — matched against the assertion's Issuer.
- **SSO URL** — the IdP's Single Sign-On endpoint.
- **SLO URL** — the IdP's Single Logout endpoint (optional).
- **X.509 Certificate** — the IdP's signing certificate (paste the PEM, or import it
  from the metadata).
- **SSO / SLO Binding** — set **HTTP-Redirect** or **HTTP-POST** to match the IdP
  (Redirect is the default and the most common).
- **NameID Format** — Email Address (default), Persistent, Transient, Unspecified, or
  Windows Domain Qualified Name, to match what the IdP sends.

If the IdP publishes a metadata URL or XML file, use **Import from Metadata** on the Add
New screen — it auto-fills the Entity ID, SSO/SLO URLs, and certificate for you.

**Certificate handling (optional):** after the certificate is set, the plugin shows its
SHA-256 fingerprint. You can **Pin** the certificate (signature verification then fails
if the fingerprint ever changes) and configure a **Rotation Strategy** (Manual, Auto
Trust, Grace Period, or Require Approval) with an optional daily/weekly metadata
**Automatic Check** so you are warned before an IdP certificate rollover breaks logins.

---

## 6. Generic OpenID Connect provider

Any OpenID Connect provider (Google Workspace, Auth0, OneLogin, and others not covered
above) connects with the same exchange.

**Give the provider these RP values** (shown on the IdP edit screen once you choose the
OpenID Connect protocol — see
[Your OpenID Connect (RP) details](#your-openid-connect-rp-details) above):

- **Redirect URI** = `https://your-site.example/?oasso_oidc_cb=1`
- **Post-logout redirect URI** = `https://your-site.example/`
- Register the client as **confidential** (it will receive a client secret) using the
  **authorization code** grant type only.

**Collect these from the provider and add them in Identity Providers → Add New:**

- **Issuer URL** — the provider's base OIDC issuer, e.g. `https://accounts.example.com`.
  Click **Fetch from discovery** after entering it to auto-fill the endpoints below from
  `/.well-known/openid-configuration`.
- **Client ID** and **Client Secret** — issued when you register the client.
- If discovery is not reachable from your WordPress server (a firewalled provider, for
  example), enter the **Authorization endpoint**, **Token endpoint**, **UserInfo
  endpoint** (optional), **JWKS URI**, and **End-session endpoint** (optional)
  individually — each one is available on the provider's own discovery document even if
  your server cannot fetch it directly.
- **Client authentication** — how the client authenticates at the token endpoint:
  **Client secret (HTTP Basic)** (the default and most widely supported), **Client
  secret (request body)**, or **None** (a public client — PKCE alone protects the
  exchange; only use this if the provider does not issue a secret).

All endpoints must be HTTPS, and the flow is always authorization code with PKCE
(S256) — see [Your OpenID Connect (RP) details](#your-openid-connect-rp-details) above
for why there is nothing to configure for either of those.

---

## Attribute and role mapping after connecting

Once the trust is established, tell the plugin what the IdP's attributes (or, for
OpenID Connect, claims) mean.

- **Attribute Mapping** (Identity Providers → edit your IdP → Attribute Mapping
  section): map each SAML attribute name — or OIDC claim name — to a WordPress user
  field — `user_email`, `first_name`, `last_name`, `display_name`, `nickname`, and
  others — or to arbitrary user meta. For SAML, if you leave it unconfigured, the plugin
  falls back to the Microsoft claim URIs for email, first name, and last name, which is
  why Entra ID often works with no manual mapping. For every other provider, and for
  OpenID Connect generally, add rows that match the exact names the provider emits —
  run **Test Connection** first (below) rather than guessing them.

- **Role Mapping** (Role Mapping tab): set a **Default Role**, and add ordered rules
  that match a SAML attribute or OIDC claim value (exact / contains / regex) to a
  WordPress role — for example, a `groups` value containing `staff` maps to `editor`.
  You can also deny login when no rule matches, and choose whether to preserve a user's
  existing roles or overwrite them on each login. Assigning administrator-level roles
  via SSO is blocked unless explicitly enabled in General Settings.

  For OpenID Connect specifically: group membership is frequently only available from
  the **UserInfo endpoint**, not the ID token (this is the default behavior on Entra ID
  past ~150 group memberships, and on Okta generally). Keep **Fetch the UserInfo
  endpoint** enabled on the IdP edit screen if your role rules key on `groups` — with it
  off, or with no UserInfo endpoint configured, those rules will never match and every
  user lands on the default role. See
  [Troubleshooting: Roles are not being assigned](troubleshooting.md#5-roles-are-not-being-assigned-oidc).

---

## Verifying with Test Connection

Before enabling Force SSO or pointing users at the IdP, verify the round-trip. This
works identically for SAML and OpenID Connect.

1. Go to **Open Access SSO → Identity Providers**.
2. Click **Test Connection** on the IdP's row. The plugin runs a real login round-trip
   — a signed AuthnRequest for SAML, or the full authorization-code-with-PKCE flow for
   OpenID Connect — and shows the result inline under **Test Results**, including every
   attribute (SAML) or claim (OIDC) it received. No WordPress session is created and no
   user is modified.
3. This is the intended way to discover an OpenID Connect provider's exact claim names
   before configuring Attribute Mapping or Role Mapping — providers vary widely (see
   [Troubleshooting: Claim names vary](troubleshooting.md#3-claim-names-vary-and-are-rarely-guessable)),
   and guessing wastes a round trip you don't need to make. Once you have run a test,
   the Attribute Mapping and Role Mapping screens offer the exact claim names as a
   dropdown instead of a free-text field.
4. If the test fails, the result explains where. Common SAML causes are a mismatched
   Entity ID/Audience, a wrong or expired IdP certificate, or a binding mismatch
   (Redirect vs. POST); relax `require_audience`/`require_assertion_expiry` on the
   Service Provider tab per the on-screen guidance only if necessary. Common OpenID
   Connect causes are covered in
   [Troubleshooting: OpenID Connect](troubleshooting.md#3-openid-connect-issues) —
   in particular a `redirect_uri` mismatch or a rejected token exchange.
5. You can also test the front-end button directly: visiting
   `https://your-site.example/?oasso_sso=1&idp=<slug>` starts login at that IdP,
   whichever protocol it uses. When more than one IdP is enabled, the login screen shows
   a chooser, and `?idp=<slug>` selects a specific one.

Keep an emergency way back in while testing Force SSO: define
`OASSO_BYPASS` to `true` in `wp-config.php`, or set a Bypass Secret Key (24+ characters)
in General Settings and append `?oasso_bypass_key=YOUR_KEY` to a login URL.
