How Keycloak SSO integration works for Drupal
Teams that run Drupal and Keycloak and want one login for editors and site users can do this with the contributed OpenID Connect module. The supported route is that module, with Keycloak acting as the OpenID Connect provider and Drupal acting as the relying party. Drupal sends the user to Keycloak, receives the result of the sign-in, and decides what the user may do on the site. Before the build starts, confirm on the OpenID Connect project page which client plugins are available for your Drupal version, because the module ships built-in clients for generic OAuth 2.0 and several named providers. If no dedicated Keycloak client is listed, plan to configure the generic OAuth 2.0 client against Keycloak's OpenID Connect endpoints.
The module authenticates users against the external provider and, by default, creates a Drupal account on first sign-in. Keycloak keeps the credentials, password policy, multi-factor settings, sessions and the realm or client definitions. Drupal keeps the content permissions, roles, user fields and the local account record that its content and revisions point to. That split is the main design decision. Decide early which identities may log in to Drupal at all, whether Keycloak groups or client roles should drive Drupal roles, and what happens to a Drupal account when the matching Keycloak user is disabled. Drupal sites often keep a local administrator account for recovery, so confirm how that account is protected and who can use it.
Treat the account-creation and role-mapping behavior as a verification item, not an assumption. Run a test sign-in for an editor, a site visitor and a disabled Keycloak user in a non-production copy, then check the resulting Drupal roles, the email and name fields, and whether a second sign-in links to the existing account instead of creating a duplicate. Record which Keycloak claims the module reads, since a missing or differently named claim is the most common cause of incorrect roles. Ask your implementation partner to document this mapping in writing so that a Keycloak upgrade or a Drupal major upgrade does not change access silently.
Prerequisites for a Keycloak and Drupal SSO build
Most delays in a Keycloak and Drupal sign-in project come from decisions made before any client is configured. The items below set the Drupal version, the Keycloak baseline, the network identity of both sites and the way modules reach production. Settle them in writing first, because each one changes what the OpenID Connect configuration looks like.
Drupal version and PHP plan
Drupal 11 requires PHP 8.3 or later and Drupal 10 requires PHP 8.1 or later. Drupal 10 reaches end of life on December 9, 2026, so a build started now on Drupal 10 will need an upgrade soon after launch. Confirm the target major version first, then confirm that the hosting platform can run the matching PHP version and that the contributed OpenID Connect module supports it.
Keycloak minor version standard
The current Keycloak release is 26.8.1, published October 13, 2026. Since Keycloak 26.0, minor releases arrive four times a year and breaking changes in minor releases are opt-in. Confirm which Keycloak 26 minor version your organization will standardize on, and record it, before writing client settings, because the admin console labels and some options differ between releases.
Production database for Keycloak
Keycloak's supported production databases include PostgreSQL 14 to 18, MariaDB, MySQL, Microsoft SQL Server, Oracle Database and Azure SQL. The default dev-file database is for development only. Confirm the database engine, its backup and restore process and whether the team will use Keycloak's automatic schema migration at startup or apply schema changes manually for a larger deployment.
DNS, TLS and callback URLs
Both the Keycloak server and the Drupal site need stable DNS names and valid TLS certificates. The Drupal redirect URI registered in Keycloak must match the public Drupal address exactly, including scheme and path, and the Keycloak issuer URL must be reachable from the Drupal server, not only from users' browsers. Plan the callback URLs for each environment, including staging, before the client is created.
Keycloak realm administration
Create or confirm a Keycloak realm that the Drupal site will use, plus at least one named administrator account with rights to create clients, mappers and roles in that realm. Decide who holds this access after launch and whether production changes go through a documented approval step. Avoid sharing the bootstrap administrator account, since it is the path back into the identity provider if other accounts fail.
Composer-based Drupal build pipeline
The OpenID Connect module and its dependencies should be installed with Composer, pinned in composer.lock and deployed through the same pipeline as the rest of the site. Confirm that the team can build, test and promote code across environments without editing files on a production server. Client secrets and the Keycloak URL belong in environment configuration, not in exported configuration files committed to the repository.
Configuring Keycloak and Drupal in the right order
This sequence moves from a clean Keycloak client to a Drupal site that signs users in, maps their claims and creates accounts only after a non-admin sign-in has been proven. Each step closes with a check, so a fault is found at the step that caused it.
Confirm the realm and its ownership
Decide whether Drupal uses a dedicated realm or an existing one, and record who administers it and who can change clients and users. Keep Drupal's login apart from unrelated applications where possible, so client changes for one system do not affect another. The step is done when the realm name, its administrators and its user population are written down and a test user exists in the realm. Confirm the choice with your Keycloak administrators, since realm structure is hard to unwind once applications depend on it.
Create a confidential client with exact redirect URIs
In the Keycloak admin console, create an OpenID Connect client with client authentication enabled, so it is confidential and holds a secret. Add one redirect URI per Drupal environment, such as development, staging and production, using the exact callback path the OpenID Connect module shows on its configuration screen. Avoid wildcards for production. The step closes when the client's settings page lists every environment's callback and the client shows a credentials tab with a secret. Ask your Keycloak team to confirm the client's scopes before you move on.
Store the client secret outside the codebase
Place the client secret in your secrets store or in environment configuration managed by your deployment tooling, not in exported configuration or the Git repository. Give each Drupal environment its own secret, and record who can read and rotate it. Check that the secret does not appear in any file under version control by searching the repository and the exported Drupal configuration. The step is done when the secret is available to the web runtime and a search of the codebase returns nothing. This matters because a leaked secret lets any holder impersonate the client.
Install and enable the OpenID Connect module
Add the contributed OpenID Connect module to the Drupal project with Composer, so the version is pinned in the lock file and deployed like other code. Enable the module with Drush or the extensions screen on a non-production environment first. Confirm that the module's configuration page loads without errors and that the Drupal status report shows no missing dependencies. The step closes when the module is enabled from version control, and the build reproduces it on a clean environment. Check the module's Drupal.org page for the Drupal core version it supports before you pin it.
Enter the issuer and client settings in Drupal
Configure a generic OpenID Connect client in Drupal with the Keycloak realm's issuer URL, the client ID and the secret read from your secrets store. Request the standard scopes your mapping depends on, and confirm the endpoints the module discovers match the realm in Keycloak. Test the login button on the login page. The closing check is a successful callback in the Drupal log and a token whose issuer and audience match the expected realm and client, which you can inspect with the developer tools or Keycloak's event log.
Map claims to Drupal user fields
Decide which token claims populate the Drupal username, email address and any profile fields, and write the mapping in the module's settings. Keep the mapping minimal and document each claim's source in Keycloak. Where a role or group claim drives access, confirm the claim name and format in a real token before mapping it. The step is done when a test sign-in populates the expected fields on the Drupal user record and an unexpected claim does not overwrite an existing value. Verify with an account whose attributes you control.
Test sign-in with a non-admin account
Sign in with an ordinary Keycloak user who has no administrative role, using an existing Drupal account that you created for the test. Confirm the user reaches the expected page, has only the roles that account should hold, and cannot reach the administration pages. Then sign in with a user from outside the allowed Keycloak group and confirm the login is denied. The step closes when both results match the access policy you wrote down earlier. Keep these test accounts in your test plan so later changes can be retested against the same cases.
Enable account creation on first sign-in
Only after the earlier tests pass, turn on account creation for first-time sign-ins in the module settings, limited to users who meet the group condition. Sign in once with a new allowed user and confirm the account is created with the mapped fields and no administrative roles. Then check the Drupal user list and the audit or watchdog log for the creation event. The step is done when the new account matches the mapping, and the denied account from the previous step still cannot create an account. Review this setting with your security team before enabling it in production.
Mapping Keycloak claims to Drupal users and fields
This table compares each identity attribute Keycloak can send with the Drupal user field it should populate, whether that value refreshes on every login, and who should own the decision. Exact claim names depend on the client scopes and mappers your team configures in Keycloak, so confirm each mapping against the OpenID Connect module documentation before go-live. The main takeaway is that email and role mappings carry the most risk, so settle those rules first.
| Identity attribute | Keycloak source | Drupal target | Updates on each login | Decision owner |
|---|---|---|---|---|
| Username or subject | Subject (sub) claim or a mapped username attribute | Drupal username plus a stored external identifier | No, set at account creation | Identity team with Drupal lead |
| Email address | Email claim from the email scope or a user attribute mapper | Drupal mail field | Yes, with a rule for changed emails | Security and Drupal lead |
| Given name | Given name claim or first name attribute mapper | First name profile field | Yes | Drupal content or site owner |
| Family name | Family name claim or last name attribute mapper | Last name profile field | Yes | Drupal content or site owner |
| Group or role claims | Group membership or client role mapper | Drupal roles through an explicit mapping table | Yes, assigned and removed by rule | Security lead with business owners |
| Locale or language | Locale claim or user language attribute | User preferred language setting | Yes, unless users change it in Drupal | Multilingual site owner |
| Account status | Enabled flag or disabled user state | Drupal account blocked or active | Yes, confirm behavior for disabled users | Identity team |
What changes for role mapping in the 2.x branch
Role mapping is where Keycloak and Drupal SSO projects most often break on upgrade, and the topic brief flags changes in the 2.x branch of the OpenID Connect module as a reason to treat it as its own piece of work. Before you choose a mapping approach, read the 2.x release notes and the issue queue on the OpenID Connect / OAuth client module project page. Look for open issues about role assignment, role removal and claim handling, and note which ones affect the exact version you plan to run. Do not assume that a mapping configured for an earlier release will behave the same way on 2.x. Confirm the behavior against the release you install, not against older blog posts or community examples.
Test two cases before go-live. The first is a role grant: a user added to the relevant Keycloak group should receive the matching Drupal role at the next sign-in. The second is a role removal: when that user leaves the group, the Drupal role should be removed as well. Many teams test only the grant, and the removal case is where stale access builds up unnoticed. Confirm in the module documentation and in your own staging environment whether removal happens at every sign-in, only under certain conditions, or through another path. Run both cases against a staging site that mirrors the production Keycloak realm, and repeat them for each release you upgrade to.
Decide up front which roles Keycloak owns and which Drupal keeps locally. Roles that describe organizational membership, such as a staff or department group, are usually good candidates for Keycloak control. Roles a site administrator assigns for editorial reasons, such as an editor role granted to a content lead, usually belong in Drupal, and the mapping configuration should never remove them during sign-in. Record this split in your design document as a short table of roles, owners and removal behavior, then check that no mapping rule can touch a locally managed role. Review the table again whenever the module or the Keycloak realm changes.
Security controls for Keycloak SSO on Drupal
These controls cover the trust between Drupal and Keycloak, the identity policy that Keycloak enforces, and the patch routine that keeps both systems current. Each one is a decision your team should record before go-live, because a gap in any of them lets a session or credential outlive the access it was meant to grant.
Confidential client with a stored secret
Register the Drupal site in Keycloak as a confidential client, so the client secret is required at the token exchange. Keep the secret out of exported configuration and out of the Drupal database in plain text, and supply it through environment variables or a secrets manager such as OpenBao. Ask who can view and rotate the secret in the Keycloak admin console, and record the rotation procedure so a leaked secret can be replaced without a site outage.
Exact redirect URIs in production
List each callback URL explicitly in the Keycloak client settings, including the scheme and host of the production Drupal site. Wildcards in redirect URIs let an attacker register a lookalike path and receive authorization codes meant for your site. Review the list during every environment change, and remove test hosts and old domains as soon as the migration that needed them is finished.
TLS on both browser and back channel
Serve Keycloak and Drupal over HTTPS, and make sure Drupal validates the Keycloak certificate chain on its server-to-server calls for the token and user-info requests. Disabling verification to clear a certificate error during setup often stays in place. Confirm that the internal CA bundle is installed on the Drupal hosts and that the certificate renewal process covers both endpoints.
MFA and password policy in Keycloak
Enforce multi-factor authentication, password rules and lockout behavior in Keycloak's authentication flows, not in Drupal. Drupal only sees the result of the login, so policies set in Drupal's own forms are bypassed when users sign in through the identity provider. Check that local Drupal password login is disabled for SSO users, or that it is restricted to a documented break-glass account.
Offboarding and the Drupal session
Disabling a user in Keycloak does not automatically end a Drupal session that is already open, and the Drupal account remains until someone blocks it. Decide whether Drupal should block the account at the next sign-in attempt or whether an administrator must act, then test both cases with a departed-user scenario. Ask how long access tokens remain valid after disablement, and set session lifetimes to match your risk tolerance.
Patch routine for both platforms
Schedule Keycloak minor releases and Drupal security releases on a single calendar. Drupal publishes security releases on the third Wednesday of each month, so use that date as the review point. Keycloak recommends manual approval for operator updates, which should be applied in a staging environment first. Track vulnerabilities in contributed modules such as the OpenID Connect client through the Drupal Security Team advisories, and assign an owner to read them each month.
Multilingual login decisions for Keycloak and Drupal
If the Drupal site and its users work in one language, most multilingual decisions drop out. The work is still configuration, because Keycloak chooses the language of the login page, error messages and required action emails from the realm settings and the user's locale. Keep the realm on one default locale and confirm that the messages in that locale match what your users read. Drupal then needs only one language, with no language negotiation to reason about.
- Realm default locale: Set the realm's default language in the Keycloak admin console so the login page does not change for visitors whose browsers send a different language.
- Supported locales: Limit the realm to the locale you can review, so users cannot switch to a language your team cannot check.
- Required action emails: Review the verify email and password reset templates in the realm email settings, since users receive these before they reach Drupal.
- Drupal language setup: Keep Drupal on a single language, and confirm that any account fields your claim mapping writes do not store a language value that conflicts with the site.
Check the default locale in each realm environment, then run a sign-in and a password reset from a clean browser profile.
On a multilingual site, the login page and emails should follow the language the visitor chose on the Drupal site. Drupal decides the current language through its language negotiation settings, such as a path prefix, a domain or the browser language. That choice must reach Keycloak on the sign-in request, and the user's preferred language must be stored consistently afterward. Test each step with real language URLs, not only the default one.
- Language negotiation in Drupal: Pick one detection method, such as path prefixes, so the sign-in link carries the visitor's language into the login flow.
- Locale hint on the request: Confirm whether the OpenID Connect module passes the current language to Keycloak as a locale hint, and test the result on each language. Check the module's project page before you promise this, at OpenID Connect / OAuth client module.
- Preferred language claim: Map a claim that carries the user's preferred language to the Drupal user's language field, and decide whether Keycloak or Drupal owns that value.
- Keycloak locale settings: Enable each supported language in the realm and confirm that every one has translated login and email messages before launch.
Check: sign in from each language URL and confirm the login page, the error page and the first email all use that language.
When the login pages must be translated, the work happens in Keycloak, not in Drupal. Keycloak renders the sign-in screens from a theme, and translated text lives in message files for each locale. Drupal's own translation covers Drupal pages only, so the sign-in and error text from Keycloak will stay in one language unless you translate it in the theme. Plan this as a separate piece of work with a named reviewer for each language.
- Custom login theme: Build a custom login theme that extends the base theme, so your changed strings stay separate from the code you do not own and survive upgrades.
- Message files per locale: Add a message file for each supported language, and keep the keys identical to the base theme so no string falls back to English by accident.
- Email templates and subjects: Translate the email bodies and subject lines alongside the login pages, because required action emails reach users before they return to Drupal.
- Review after upgrades: Retest each language after every Keycloak upgrade, since new message keys can appear and untranslated keys fall back to the default text.
Check: compare the keys in each locale file against the base theme and have a native reader sign off each language before launch.
Common Keycloak and Drupal SSO failures and fixes
This table pairs common Keycloak and Drupal sign-in failures with their likely causes, the checks that confirm each cause, and the fix to apply. Read it top to bottom during testing, or jump to the symptom that matches the error your users see. Most failures trace back to a mismatch between what Drupal sends and what the Keycloak client expects.
| Symptom | Likely cause | Check | Fix |
|---|---|---|---|
| Keycloak shows an invalid redirect URI error after sign-in | Drupal's callback path does not match a valid redirect URI on the Keycloak client | Compare the redirect URI in the client settings with the callback path shown in the Drupal OpenID Connect configuration, including scheme, host and trailing slash | Add the exact Drupal callback URL to the client's valid redirect URIs, then retest from a private browser window |
| Token exchange fails with unauthorized client or invalid secret after rotation | The client secret was regenerated in Keycloak but the Drupal configuration still holds the old value | Check the Keycloak client credentials tab and the Drupal client secret field, and review the Drupal log for token endpoint errors | Enter the new secret in Drupal, clear caches, and store the value in your secrets manager so future rotations stay in sync |
| Discovery fails or the login button is missing | Issuer or discovery URL points at the wrong realm or a misspelled realm name | Open the realm's well-known OpenID configuration URL in a browser and confirm the issuer value matches the one in Drupal exactly | Correct the issuer to the target realm, then confirm endpoints resolve from the Drupal server, not just from your workstation |
| Tokens are rejected with messages about tokens not yet valid or expired | Clock skew between the Keycloak host, the Drupal web servers and the token issuer | Compare UTC time on each host and check whether the failures cluster on one node | Synchronize all hosts with a time service, then confirm the failures stop before changing token lifetime settings |
| Users are blocked or sign-in creates a duplicate or fails with an email conflict | An existing Drupal account already uses the same email address as the incoming Keycloak user | Search the Drupal people list for the email, and review how the module matches existing accounts (by username, email or subject identifier) | Decide the matching rule in the design phase, link or migrate existing accounts deliberately, and resolve duplicates before go-live |
| Users sign in but lack expected roles | The claim Drupal reads for roles has a different name or structure than the one Keycloak sends | Decode a sample ID or access token for a test user and compare claim names with the role mapping configured in Drupal | Align the claim name in the mapping, or add a client scope mapper in Keycloak that emits the claim, then retest with a test account |
| Users are locked out after a Keycloak upgrade | A minor or major release changed defaults, endpoints, client settings or the database schema, or an automatic upgrade ran unexpectedly | Review the Keycloak release notes and upgrading guide for the versions crossed, check the server logs for schema or configuration warnings, and confirm the Drupal module version supports the new flow | Pin the Keycloak version, review the release changes in staging first, and use manual approval for operator updates where the Operator is in use |
| Login loops back to the sign-in page behind a reverse proxy | The proxy does not forward the original protocol header, so Keycloak or Drupal builds http redirect URLs for an https site | Inspect response headers and the redirect chain with a browser developer tool, and confirm the proxy forwards the protocol and host headers to both services | Configure the proxy to pass the forwarded protocol and host headers, set Keycloak's proxy mode for your topology, and confirm Drupal's trusted host and reverse proxy settings match |
Questions teams ask before building Keycloak SSO for Drupal
What drives the cost of Keycloak SSO for Drupal?
The cost is driven mainly by how many Drupal environments need sign-in, how complex the claim and role model is, how many languages the login pages must support, how many existing accounts must be matched, and whether Keycloak is already running in production. Each of these adds configuration, testing and cutover work. A new Keycloak deployment adds infrastructure and database decisions on top of the Drupal work. Keycloak and the OpenID Connect module are open source, so license fees are not the cost driver. The cost is labor: planning, configuration, testing and handover. Ask any partner for a quote that separates one-time build work from recurring support, and that lists each environment and language in scope.
How long does a Keycloak SSO integration for Drupal take?
The duration depends on the same factors that drive cost: the number of environments, the role model, the languages, the user matching rules and the state of your Keycloak service. A team that already runs Keycloak on a supported database with a tested high availability design has less to build than a team starting from zero. No duration is fixed here. Ask for a timeline in the written scope, and check that it includes time for a staging test with real test accounts, a cutover plan for existing users and a rollback step.
What does our team need to provide before the work starts?
Your team needs to provide a Keycloak instance or a decision to deploy one, administrator access to create a realm and clients, the Drupal environments that will use sign-in, and a list of the roles and groups that should map to Drupal roles. You also need a decision on how existing Drupal accounts will be matched to Keycloak users, and the list of languages for the login pages. Named contacts for Keycloak, Drupal and identity policy should be available for decisions during the build. Confirm the exact access model in your own environment before the scope is signed.
Can our internal team build Keycloak SSO for Drupal alone?
An internal team with Drupal and Keycloak experience can build the integration, and the work is well documented on Drupal.org and keycloak.org. The main risks are in the claim and role model, the account matching rules and the testing of sign-in across environments, languages and existing users. Teams without recent Keycloak administration experience often find the realm, client and token settings take longer than the Drupal module configuration. Compare your team's current skills against the list of tasks in the scope, and decide whether to build in house, bring in a partner for the design and handover, or buy ongoing support.
Do we need to upgrade Keycloak and Drupal together?
No, they are separate systems and you do not have to upgrade them at the same time, but you do need to check compatibility at each step. Keycloak documents that breaking changes in minor releases are opt-in, and it plans four minor releases a year. Drupal has its own release schedule, and the OpenID Connect module must be checked against the Drupal version you run. Plan each upgrade in a staging environment with test sign-ins for every client. Keep Keycloak's upgrade notes and the Drupal module release notes with the change record, and check the Keycloak upgrading guide before each move.
Does Keycloak have to run on Kubernetes for Drupal SSO?
No. Keycloak does not require Kubernetes for this integration, and the Drupal module only needs a reachable OpenID Connect endpoint. Keycloak can run on virtual machines or bare metal you control, provided it uses a supported production database and a high availability design with a synchronously replicated database. The Keycloak Operator is one installation option, installed through Operator Lifecycle Manager, kubectl or an experimental Helm chart. Choose the hosting model based on the platform your operations team already runs and supports.
What should a written quote for Keycloak SSO for Drupal include?
A written quote should list the scope in plain terms, including each Drupal environment, each Keycloak realm and client, the role and group mapping rules, the languages and the existing user matching method. It should name the deliverables, such as configuration documentation, test cases, a cutover runbook and a handover session. It should state what is excluded, such as Keycloak infrastructure, database or high availability work if those are out of scope. Ask for the assumptions the timeline depends on, the client responsibilities, the acceptance steps and the separate cost of any ongoing support. Fixed-scope quotes are agreed in writing before work starts, so make sure the scope is complete before you sign.
Is a Keycloak SSO integration for Drupal ready for a compliance review?
The integration can be documented in a way that supports a compliance review, but DeployOpen does not issue audit reports, attestations or certifications. Independent auditors and certification bodies make those determinations. Useful evidence includes the realm and client configuration, the list of roles and their mapping rules, test results for sign-in and sign-out, access reviews for administrators, and the logs kept from Keycloak and Drupal. Ask your auditor which controls apply to your organization and which evidence they expect, before the build begins.
How DeployOpen scopes and delivers Keycloak SSO for Drupal
DeployOpen plans, builds, documents and supports Keycloak and Drupal SSO integration inside infrastructure you control, whether that is your cloud accounts, data centers or air-gapped network. Engagements are fixed-scope, with the scope, deliverables and timeline agreed in writing before work starts.
How we scope
- Written scope covering the Keycloak realm, Drupal OpenID Connect client, user field and email sync rules, and role mapping
- Confirmation of the Keycloak version, Drupal branch and PHP version your environment will run
- Agreed decisions on multilingual login, account creation on first sign-in, and which users may access the site
How we build
- Configure the Keycloak client and the Drupal module on a staging site first, with test accounts for each role
- Test login, logout, account linking, email changes and role changes across every language your site serves
- Record configuration, secrets handling and exceptions in a runbook your team can review and change
How we hand over
- Documented configuration with the Keycloak client settings, module settings and mapping tables your team owns
- Walkthrough with administrators on rotating client secrets, adding roles and reviewing failed sign-ins
- Test evidence from the verification pass so your team and any assessor can see what was checked
How we support
- Ongoing support, upgrades and continuous testing are available as a retainer after handover
- Retainer scope can cover reviewing Keycloak and Drupal module release notes before each planned upgrade
- Ask in your quote which items a retainer covers and how changes to the written scope are priced

