
Seamlessly integrate Keycloak authentication with Strapi Admin Panel.
released March 13, 2026
npm install strapi-keycloak-passportEnterprise-grade Keycloak authentication for Strapi v5 Admin Panel with full RBAC support.
yarn add strapi-keycloak-passportor
npm install strapi-keycloak-passportAdd to your config/plugins.js (or config/plugins.ts):
module.exports = ({ env }) => ({
'strapi-keycloak-passport': {
enabled: env.bool('KEYCLOAK_ENABLED', true),
config: {
// Required: Keycloak server URL (without trailing slash)
KEYCLOAK_AUTH_URL: env('KEYCLOAK_AUTH_URL', 'https://keycloak.example.com'),
// Required: Keycloak realm name
KEYCLOAK_REALM: env('KEYCLOAK_REALM', 'master'),
// Required: OAuth client credentials
KEYCLOAK_CLIENT_ID: env('KEYCLOAK_CLIENT_ID', 'strapi-admin'),
KEYCLOAK_CLIENT_SECRET: env('KEYCLOAK_CLIENT_SECRET'),
// Optional: Set to true for Keycloak versions < 17 (uses /auth prefix)
KEYCLOAK_LEGACY_MODE: env.bool('KEYCLOAK_LEGACY_MODE', false),
// Optional: Role configuration
roleConfigs: {
// Default Strapi role ID when no mapping exists
defaultRoleId: env.int('KEYCLOAK_DEFAULT_ROLE_ID', 1),
// Keycloak roles to exclude from the mapping UI
excludedRoles: [
'uma_authorization',
'offline_access',
'default-roles-master',
],
},
},
},
});# Required
KEYCLOAK_AUTH_URL=https://keycloak.example.com
KEYCLOAK_REALM=master
KEYCLOAK_CLIENT_ID=strapi-admin
KEYCLOAK_CLIENT_SECRET=your-client-secret
# Optional
KEYCLOAK_ENABLED=true
KEYCLOAK_LEGACY_MODE=false
KEYCLOAK_DEFAULT_ROLE_ID=1| Keycloak Version | KEYCLOAK_LEGACY_MODE | URL Format |
|---|---|---|
| 17+ (Quarkus) | false (default) | https://keycloak.example.com/realms/{realm}/... |
| < 17 (WildFly) | true | https://keycloak.example.com/auth/realms/{realm}/... |
strapi-adminopenid-connectOn (Confidential)https://your-strapi-instance.comhttps://your-strapi-instance.com/admin/*https://your-strapi-instance.comFor the plugin to fetch user roles, the client needs realm-management permissions:
strapi-admin → Service Account Rolesview-usersview-realmmanage-users (optional, for future features)STRAPI_SUPER_ADMINSTRAPI_EDITORSTRAPI_AUTHOR| Keycloak Role | Strapi Role |
|---|---|
STRAPI_SUPER_ADMIN | Super Admin (1) |
STRAPI_EDITOR | Editor (2) |
STRAPI_AUTHOR | Author (3) |
defaultRoleId role┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ User │ │ Strapi │ │ Keycloak │
└──────┬──────┘ └──────┬──────┘ └──────┬──────┘
│ │ │
│ 1. POST /admin/login │ │
│ (email + password) │ │
│─────────────────────────────────>│ │
│ │ │
│ │ 2. OAuth2 Password Grant │
│ │─────────────────────────────────>│
│ │ │
│ │ 3. Access Token │
│ │<─────────────────────────────────│
│ │ │
│ │ 4. GET /userinfo │
│ │─────────────────────────────────>│
│ │ │
│ │ 5. User Info + Roles │
│ │<─────────────────────────────────│
│ │ │
│ │ 6. Find/Create Admin User │
│ │ 7. Map Roles │
│ │ 8. Generate Strapi JWT │
│ │ │
│ 9. JWT Token + User │ │
│<─────────────────────────────────│ │
│ │ │All endpoints are prefixed with /strapi-keycloak-passport/
| Method | Endpoint | Description | Auth |
|---|---|---|---|
POST | /admin/login | Authenticate via Keycloak | No |
GET | /keycloak-roles | Fetch available Keycloak & Strapi roles | Yes |
GET | /get-keycloak-role-mappings | Get saved role mappings | Yes |
POST | /save-keycloak-role-mappings | Save role mappings | Yes |
GET | /test-connection | Test Keycloak connectivity | Yes |
GET | /token-cache-stats | Get token cache statistics | Yes |
POST | /invalidate-token | Invalidate cached admin token | Yes |
Admin tokens are cached in-memory with automatic refresh:
serverUrl:realm:clientId/token-cache-stats endpointAll authentication events are logged to the database:
| Event | Logged Data |
|---|---|
| Login Success | User email, Keycloak ID, assigned roles, IP, user agent |
| Login Failure | Attempted email, failure reason, IP, user agent |
| User Created | Email, Strapi ID, Keycloak ID, assigned roles |
| User Updated | Email, changed fields (roles, name, etc.) |
| Role Mapping Changed | Keycloak role, Strapi role, performed by |
Query audit logs via Strapi's Content Manager or API.
The plugin implements a sanitized error pattern:
KEYCLOAK_AUTH_URL is correct (no trailing slash)KEYCLOAK_LEGACY_MODE matches your Keycloak versionview-users and view-realm roles assignedexcludedRoles configurationUse the built-in connection test:
curl -X GET "https://your-strapi.com/strapi-keycloak-passport/test-connection" \
-H "Authorization: Bearer YOUR_ADMIN_TOKEN"KEYCLOAK_LEGACY_MODE option/test-connection, /token-cache-stats, /invalidate-tokenKEYCLOAK_TOKEN_URL, KEYCLOAK_USERINFO_URL)Contributions are welcome! Please read our contributing guidelines before submitting PRs.
MIT License - see LICENSE for details.
Share your work with the community and get it listed in the Strapi ecosystem for everyone to discover and use.
Submit
