Drupal Integration
This guide covers how to integrate Skycloak authentication into Drupal sites using the OpenID Connect contributed module, which supports generic OIDC providers out of the box.
OIDC vs. SAML for Drupal
Most Drupal sites standardize on OpenID Connect for SSO — the openid_connect module is actively maintained, ships a Generic provider plugin that works with any OIDC-compliant issuer (including Skycloak), and needs no XML metadata exchange. If your organization instead requires SAML (common in some enterprise/education deployments with existing SAML infrastructure), use the simplesamlphp_auth module against Skycloak’s SAML endpoints instead — the realm and client concepts below still apply, only the protocol config differs.
Prerequisites
- Drupal 10.x or 11.x site
- Composer-based Drupal installation (required to install contrib modules)
- Skycloak cluster with configured realm and client
- Admin access to the Drupal site
Quick Start
1. Create an Application in Skycloak
- In Skycloak, navigate to your cluster → Applications → Create Application
- Set Application Type to
Confidential(Drupal exchanges the authorization code server-side) - Add Redirect URIs:
https://your-drupal-site.com/openid-connect/skycloak(the module’s fixed callback path — see step 4) - After creation, copy the Client ID and Client Secret from the credentials tab
2. Install the Module
composer require drupal/openid_connect
drush en openid_connect -y3. Configure the Generic Provider
- Go to Configuration → Web services → OpenID Connect (
/admin/config/people/openid-connect) - Under Generic provider, click Configure (enable it first if not already enabled)
- Fill in the client settings:
- Client ID: your Application’s Client ID from Step 1
- Client secret: your Application’s Client Secret from Step 1
-
Authorization endpoint:
https://your-cluster-id.app.skycloak.io/realms/your-realm/protocol/openid-connect/auth -
Token endpoint:
https://your-cluster-id.app.skycloak.io/realms/your-realm/protocol/openid-connect/token -
UserInfo endpoint:
https://your-cluster-id.app.skycloak.io/realms/your-realm/protocol/openid-connect/userinfo -
End session endpoint:
https://your-cluster-id.app.skycloak.io/realms/your-realm/protocol/openid-connect/logout
- Save configuration
The module’s redirect URI for any provider is always https://your-drupal-site.com/openid-connect/<provider-machine-name> — confirm this matches what you registered in Step 1 (for the Generic provider it’s openid-connect/generic unless you renamed it).
4. Set Login Behavior
Under Configuration → OpenID Connect → Settings:
- User login behavior: choose whether OIDC login is optional (Drupal login form stays, with an added “Log in with Skycloak” button) or the only login method
-
Attribute mapping: map
preferred_username→ Drupal username,email→ Drupal email,name→ Display name - Enable Override registration settings if you want Skycloak-authenticated users auto-created even when Drupal’s own registration is closed
Role Mapping
Map Keycloak realm roles to Drupal roles so permissions stay centrally managed in Skycloak:
- Go to Configuration → OpenID Connect → Claim mapping (or install the companion openid_connect_extras submodule for advanced role-sync rules)
- Set the roles claim source to
realm_access.roles(the standard location for Keycloak realm roles in the ID token) - Add mapping rules, for example:
-
admin(Keycloak realm role) →administrator(Drupal role) -
editor(Keycloak realm role) →content_editor(Drupal role)
-
- Choose whether to only add mapped roles on login, or also remove Drupal roles no longer present in the token (recommended for centralized deprovisioning)
Programmatic Access (Custom Module)
For custom logic beyond the UI-configurable mapping, hook into the module’s login event:
<?php
/**
* Implements hook_openid_connect_userinfo_save().
*
* Syncs additional Skycloak claims onto the Drupal user entity
* beyond what the module's built-in attribute mapping covers.
*/
function mymodule_openid_connect_userinfo_save(\Drupal\user\UserInterface $account, array $context) {
$userinfo = $context['userinfo'];
if (!empty($userinfo['department'])) {
$account->set('field_department', $userinfo['department']);
$account->save();
}
}<?php
/**
* Implements hook_openid_connect_pre_authorize().
*
* Blocks login for users missing email_verified, mirroring the
* verify-wall enforced on other Skycloak-backed applications.
*/
function mymodule_openid_connect_pre_authorize(array $context) {
$userinfo = $context['userinfo'] ?? [];
if (isset($userinfo['email_verified']) && !$userinfo['email_verified']) {
return FALSE;
}
return NULL;
}Single Logout
Enable Drupal-initiated logout to also end the Skycloak session:
- Under Configuration → OpenID Connect → Settings, enable “Send end session request on logout”
- This calls the End session endpoint configured in Step 3 with the stored
id_token_hint, ending the SSO session cluster-side as well as the local Drupal session
Production Considerations
- Store the Client Secret via Drupal’s Key module backed by an environment variable or secrets manager, not directly in exported config (
config/sync/openid_connect.settings.generic.yml) — that file is typically committed to version control. - Serve the site over HTTPS; Keycloak rejects
http://redirect URIs for confidential clients in most realm security profiles. - If running Drupal behind a CDN/reverse proxy, ensure
$settings['reverse_proxy'] = TRUE(and trusted proxy IPs) are set insettings.phpso the module generates the correct external host in redirect and callback URLs.
Troubleshooting
-
“Invalid redirect_uri” from Skycloak — the module derives its callback path from the provider’s machine name (
openid-connect/genericby default); double-check this exactly matches the Redirect URI registered on the Application, including scheme. -
Users created but with no email — the userinfo endpoint must return an
emailclaim; confirm the client’s assigned scopes in Skycloak includeemailand that attribute mapping targets Drupal’s mail field. - Roles not syncing on subsequent logins — role mapping only reapplies on login; if you rely on real-time deprovisioning, ensure “remove roles no longer present” is enabled rather than relying on a periodic batch sync.
-
Blank page after callback — check Drupal’s logs (
/admin/reports/dblog) for the specific OIDC error; a common cause is a token endpoint returning a client authentication failure due to a mismatched Client Secret after a rotation in Skycloak.
Next Steps
- WordPress - Comparable SSO setup for the other major CMS platform
- Add social login providers
- Configure multi-factor authentication