install
source · Clone the upstream repo
git clone https://github.com/ComeOnOliver/skillshub
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/ComeOnOliver/skillshub "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/TerminalSkills/skills/keycloak" ~/.claude/skills/comeonoliver-skillshub-keycloak && rm -rf "$T"
manifest:
skills/TerminalSkills/skills/keycloak/SKILL.mdsource content
Keycloak — Open-Source Identity and Access Management
You are an expert in Keycloak, the open-source identity and access management solution by Red Hat. You help teams implement single sign-on (SSO), OAuth 2.0, OpenID Connect, SAML 2.0, user federation (LDAP/Active Directory), social login, multi-factor authentication, and fine-grained authorization — providing enterprise-grade identity management that can be self-hosted and customized.
Core Capabilities
Setup
# docker-compose.yml — Keycloak with PostgreSQL version: "3.8" services: keycloak: image: quay.io/keycloak/keycloak:24.0 command: start-dev environment: KC_DB: postgres KC_DB_URL: jdbc:postgresql://postgres:5432/keycloak KC_DB_USERNAME: keycloak KC_DB_PASSWORD: ${KC_DB_PASSWORD} KEYCLOAK_ADMIN: admin KEYCLOAK_ADMIN_PASSWORD: ${KC_ADMIN_PASSWORD} KC_HOSTNAME: auth.example.com KC_PROXY_HEADERS: xforwarded ports: - "8080:8080" depends_on: - postgres postgres: image: postgres:16 environment: POSTGRES_DB: keycloak POSTGRES_USER: keycloak POSTGRES_PASSWORD: ${KC_DB_PASSWORD} volumes: - pg_data:/var/lib/postgresql/data volumes: pg_data:
Client Integration (Next.js)
// src/lib/auth.ts — Keycloak OIDC integration import NextAuth from "next-auth"; import KeycloakProvider from "next-auth/providers/keycloak"; export const { handlers, signIn, signOut, auth } = NextAuth({ providers: [ KeycloakProvider({ clientId: process.env.KEYCLOAK_CLIENT_ID!, clientSecret: process.env.KEYCLOAK_CLIENT_SECRET!, issuer: `${process.env.KEYCLOAK_URL}/realms/${process.env.KEYCLOAK_REALM}`, }), ], callbacks: { async jwt({ token, account }) { if (account) { token.accessToken = account.access_token; token.refreshToken = account.refresh_token; token.idToken = account.id_token; } return token; }, async session({ session, token }) { session.accessToken = token.accessToken as string; return session; }, }, });
Admin API
// Keycloak Admin REST API — manage users programmatically const KEYCLOAK_URL = process.env.KEYCLOAK_URL; const REALM = process.env.KEYCLOAK_REALM; async function getAdminToken(): Promise<string> { const res = await fetch( `${KEYCLOAK_URL}/realms/master/protocol/openid-connect/token`, { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded" }, body: new URLSearchParams({ grant_type: "client_credentials", client_id: "admin-cli", client_secret: process.env.KEYCLOAK_ADMIN_SECRET!, }), }, ); const { access_token } = await res.json(); return access_token; } async function createUser(userData: { username: string; email: string; firstName: string; lastName: string; }) { const token = await getAdminToken(); await fetch(`${KEYCLOAK_URL}/admin/realms/${REALM}/users`, { method: "POST", headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json", }, body: JSON.stringify({ ...userData, enabled: true, emailVerified: true, credentials: [{ type: "password", value: "temp123", temporary: true }], }), }); } async function assignRole(userId: string, roleName: string) { const token = await getAdminToken(); // Get role const rolesRes = await fetch( `${KEYCLOAK_URL}/admin/realms/${REALM}/roles/${roleName}`, { headers: { Authorization: `Bearer ${token}` } }, ); const role = await rolesRes.json(); // Assign to user await fetch( `${KEYCLOAK_URL}/admin/realms/${REALM}/users/${userId}/role-mappings/realm`, { method: "POST", headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json" }, body: JSON.stringify([role]), }, ); }
Realm Configuration
## Key Concepts ### Realm - Isolated namespace for users, clients, roles - Each realm has its own login page, user database, settings - Example: "production" realm, "staging" realm ### Clients - Applications that authenticate via Keycloak - Types: public (SPA), confidential (backend), bearer-only (API) - Configure redirect URIs, CORS, token lifetimes ### Roles - Realm roles: global across all clients (admin, user, moderator) - Client roles: scoped to a specific application (api:read, api:write) - Composite roles: combine multiple roles into one ### Identity Providers - Social: Google, GitHub, Facebook, Apple, Microsoft - Enterprise: SAML (Okta, Azure AD), LDAP, Active Directory - Custom: any OIDC/SAML 2.0 provider ### Authentication Flows - Username/password + OTP (TOTP/HOTP) - WebAuthn (passkeys, security keys) - Custom flows (conditional OTP, required actions)
Installation
# Docker (development) docker run -p 8080:8080 -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=admin \ quay.io/keycloak/keycloak:24.0 start-dev # Production docker run -e KC_DB=postgres -e KC_HOSTNAME=auth.example.com \ quay.io/keycloak/keycloak:24.0 start --optimized # Kubernetes (Helm) helm install keycloak bitnami/keycloak
Best Practices
- Realm per environment — Separate realms for dev/staging/production; export/import configs between them
- Confidential clients for backends — Use client secret authentication; never expose secrets in frontend apps
- RBAC with roles — Map business roles (admin, editor, viewer) to Keycloak realm/client roles
- Social login — Enable Google/GitHub for developer tools, Google/Apple for consumer apps
- Token lifetimes — Access tokens: 5 minutes; refresh tokens: 30 days; balance security vs UX
- MFA for admins — Require TOTP or WebAuthn for all admin and privileged accounts
- User federation — Connect to existing LDAP/AD; Keycloak syncs users without migration
- Export realm config — Export realm as JSON; store in Git for reproducible deployments