Keyway SSO for Craft CMS › Guides
What to put in Okta's app integration, what to paste back into Craft, and which of Okta's defaults will quietly break the second login if you leave them alone. Okta's admin console changes wording from time to time — where a name below does not match what you see, look for the setting that does the same job.
Verification status, plainly. This guide covers SAML 2.0 with Okta, and that path was run end to end against a live Okta tenant on 17 September 2026 (Integrator Free Plan, fresh Craft 5.11 install on default settings): the first sign-in created the account just in time with the mapped group, and the second one updated it and reached the control panel. Single Logout will not work with Okta — by Okta's own documentation (read 17 September 2026) Okta will not send a logout request to the application after an ordinary Okta sign-out; that half was not exercised on the live tenant. With Okta as your only provider, plan on single sign-on and not single logout. OpenID Connect with Okta has not been checked — the OIDC side of the plugin is written to the specification and exercised against a different provider, so if you go that way, treat it as unverified and test it carefully before anyone depends on it.
SAML 2.0.Sign in with SSO,
at most 120 characters).You may type those two values into SP entity ID and ACS URL now, but do not expect the save to go through yet and do not expect the metadata file: the save is rejected until Okta's three values are in too, and a rejected save stores nothing. Create the application first.
Create a new app integration of the SAML 2.0 kind, give it a name, then work through its SAML settings:
| Okta setting | Value |
|---|---|
| Single sign-on URL | the ACS URL this site answers on value from Step 1 |
| Use this for Recipient URL and Destination URL | leave it checked |
| Audience URI (SP Entity ID) | exactly what you put in SP entity ID |
| Default RelayState | leave empty |
| Name ID format | EmailAddress — and not Unspecified or Transient |
| Application username | Email |
The Recipient and Destination checkbox is load-bearing. The plugin compares
the response's Destination attribute (when present) and the assertion's
SubjectConfirmationData/@Recipient against the configured ACS URL,
exactly, with no substring or prefix leniency and no way to relax it. If those three addresses
are not the same string, the login fails with destination_mismatch or
confirmation_invalid.
The Name ID format has to be a stable one. Accounts this plugin creates are
recognised on later logins by account, issuer and Name ID.
Transient is a new value on every login by definition, which means the
second login of every user is refused with linking_disabled. Use
EmailAddress or Persistent. The plugin does not read the format
attribute, so there is no error message pointing at this.
Attribute statements. Add three, with these names exactly — the plugin matches
on the attribute's Name: email → user.email,
firstName → user.firstName, lastName →
user.lastName.
Group attribute statement. For group mapping, add one named
groups with the filter Matches regex and the expression
.*. That sends every Okta group the user belongs to; the narrowing happens in Craft,
in the Groups table.
Signing. The assertion must be signed, with RSA-SHA256. The plugin requires a signed assertion unconditionally. Leave assertion encryption off unless you have a reason for it — there is no field for an SP certificate here, so a certificate matching your private key would have to reach Okta by another route.
Assign somebody, then collect three values from the app's sign-on settings — usually behind the link with the SAML setup instructions:
| Craft field | Okta value |
|---|---|
| IdP SSO URL | Identity Provider Single Sign-On URL |
| IdP entity ID | Identity Provider Issuer |
| IdP signing certificate | the X.509 Certificate, in PEM form (the -----BEGIN CERTIFICATE----- block) |
In the SAML 2.0 section: IdP entity ID takes Okta's
Identity Provider Issuer (compared byte for byte against the assertion issuer),
IdP signing certificate the full certificate (a fingerprint is rejected),
IdP SSO URL Okta's sign-on URL — required, because without it there is nowhere
to send the browser. SP entity ID and ACS URL repeat what you
gave Okta. Clock skew (seconds) defaults to 60 and caps at
120.
Leave SP private key empty unless you turned on encrypted assertions, and leave the logout fields empty too on an Okta installation — see the limits below for why.
Save and read the screen. Under ACS URL the plugin comments on what you typed: no message means it is identical to the address this site answers on; anything else describes exactly how it differs. A banner saying the connection "is not usable yet" means the login screen still offers password login only.
An empty Attributes table does not mean "map nothing" — it means "use the
shipped defaults", and those defaults are exactly what Step 2 configures in Okta:
email → email (required), firstName →
firstName, lastName → lastName. So with the attribute
statements above you can leave the table alone.
Groups. Source attributes defaults to groups.
Each row of the Groups table maps an Okta group to a Craft group handle with
Exact, Prefix or Suffix matching; there are no
regular expressions, on purpose. Prefix and suffix patterns must be at least two characters, and
an empty pattern is refused — it would match everything Okta sends. Sync mode is
Append by default; Replace makes Okta the only source of truth, which
also means a login mapping to nothing empties the account's group list.
Allow admin escalation is off by default and worth leaving off: with it on,
whoever administers your Okta groups can grant Craft admin. Detail:
group mapping.
Provisioning. Create accounts on first login and
Update accounts on every login are on by default; Match existing accounts
by is E-mail. Link to existing Craft accounts is
off, so a Craft account that already exists with the same address is not adopted
until you say so — and Linking may include admin accounts is a separate switch,
because "let the team sign in with SSO" and "let Okta hand out the owner's account" are not the
same sentence.
Keep at least one Craft admin whose password you know, and confirm that password still works before you rely on it. Admins may still use a password is on by default, and if your settings would leave nobody able to reach the control panel when Okta is unreachable, the plugin turns it back on as you save and says so. It checks the settings, not the accounts: an Emergency accounts entry only counts if it names an existing account with a local Craft password — and accounts this plugin created from Okta logins have none. Full detail: password login and lockout.
Then open the Craft login screen in a private window and sign in as the user you assigned. The
SSO button appears only when the configuration is usable. Afterwards open Open sign-in
diagnostics — after a success as well as after a failure. If the panel reports that the
diagnostics store is unavailable, the migration has not run: php craft up.
A login has five minutes between pressing the SSO button and the assertion coming back; after that the single-use login state has expired. That is a stale browser tab, not a session length.
LogoutRequest, the plugin ends the matching Craft session. Signing out of Craft
does not end the session at your identity provider, and Okta will not send such a request after
an ordinary Okta sign-out — so with Okta as your only provider, plan on single sign-on, not
single logout. Verified end to end against Keycloak 26.0; OpenID Connect has no logout
support. Okta issues a LogoutRequest to an application only as the
continuation of a logout that began at another SAML application, and turning Single
Logout on for an Okta application requires the service provider to be able to send Okta a
signed logout request in the first place — which is exactly the half this
plugin does not have. Okta describes both points in
Single
Logout and
Configure SAML Single
Logout (read 17 September 2026). Day to day: the two sessions are independent, so on a
shared machine the instruction to give people is sign out twice, once in Craft
and once in Okta. Leave the logout fields empty on an Okta installation — no Okta
LogoutRequest has been observed arriving at a Craft install.NameIDFormat in our metadata is unspecified, so
the metadata file will not set EmailAddress for you — set it in Okta yourself.This list covers what is specific to Okta. The limits that apply to every provider are on the troubleshooting page; read them once before you go live.
SAML 2.0 and OpenID Connect sign-in for the Craft control panel: attribute and group mapping, just-in-time accounts, an admin password fallback with a guard that switches admin password login back on, with a warning, if your settings would otherwise leave nobody able to sign in, and a diagnostics screen that tells you why a login was refused. The plugin is in final testing and is on its way to the Craft Plugin Store.