Smithery Logo
MCPsSkillsDocsPricing
Login
Smithery Logo

Accelerating the Agent Economy

Resources

DocumentationPrivacy PolicySystem Status

Company

PricingAboutBlog

Connect

© 2026 Smithery. All rights reserved.

    oriolrius

    keycloak

    oriolrius/keycloak
    Security
    4

    About

    SKILL.md

    Install

    Install via Skills CLI

    or add to your agent
    • Claude Code
      Claude Code
    • Codex
      Codex
    • OpenClaw
      OpenClaw
    • Cursor
      Cursor
    • Amp
      Amp
    • GitHub Copilot
      GitHub Copilot
    • Gemini CLI
      Gemini CLI
    • Kilo Code
      Kilo Code
    • Junie
      Junie
    • Replit
      Replit
    • Windsurf
      Windsurf
    • Cline
      Cline
    • Continue
      Continue
    • OpenCode
      OpenCode
    • OpenHands
      OpenHands
    • Roo Code
      Roo Code
    • Augment
      Augment
    • Goose
      Goose
    • Trae
      Trae
    • Zencoder
      Zencoder
    • Antigravity
      Antigravity
    ├─
    ├─
    └─

    About

    Expert guidance for Keycloak identity and access management including realm configuration, client setup, user federation, authentication flows, role-based access control, and integration with...

    SKILL.md

    Keycloak

    Expert assistance with Keycloak identity and access management platform.

    Overview

    Keycloak is an open-source Identity and Access Management (IAM) solution providing:

    • Single Sign-On (SSO)
    • Identity brokering and social login
    • User federation (LDAP/Active Directory)
    • Standard protocols (OAuth 2.0, OpenID Connect, SAML 2.0)
    • Fine-grained authorization
    • Admin console and account management

    Installation & Setup

    Docker (Quick Start)

    # Run Keycloak
    docker run -d \
      --name keycloak \
      -p 8080:8080 \
      -e KEYCLOAK_ADMIN=admin \
      -e KEYCLOAK_ADMIN_PASSWORD=admin \
      quay.io/keycloak/keycloak:latest start-dev
    
    # With PostgreSQL
    docker run -d \
      --name keycloak \
      -p 8080:8080 \
      -e KC_DB=postgres \
      -e KC_DB_URL=jdbc:postgresql://localhost/keycloak \
      -e KC_DB_USERNAME=keycloak \
      -e KC_DB_PASSWORD=password \
      -e KEYCLOAK_ADMIN=admin \
      -e KEYCLOAK_ADMIN_PASSWORD=admin \
      quay.io/keycloak/keycloak:latest start
    

    Docker Compose

    version: '3'
    
    services:
      postgres:
        image: postgres:15
        environment:
          POSTGRES_DB: keycloak
          POSTGRES_USER: keycloak
          POSTGRES_PASSWORD: password
        volumes:
          - postgres_data:/var/lib/postgresql/data
    
      keycloak:
        image: quay.io/keycloak/keycloak:latest
        command: start
        environment:
          KC_DB: postgres
          KC_DB_URL: jdbc:postgresql://postgres/keycloak
          KC_DB_USERNAME: keycloak
          KC_DB_PASSWORD: password
          KEYCLOAK_ADMIN: admin
          KEYCLOAK_ADMIN_PASSWORD: admin
          KC_HOSTNAME: localhost
          KC_HOSTNAME_PORT: 8080
          KC_HOSTNAME_STRICT_HTTPS: false
          KC_HTTP_ENABLED: true
        ports:
          - "8080:8080"
        depends_on:
          - postgres
    
    volumes:
      postgres_data:
    

    Production Setup

    # Build with PostgreSQL support
    docker run \
      -e KC_DB=postgres \
      -e KC_FEATURES=token-exchange,admin-fine-grained-authz \
      -e KC_HTTP_ENABLED=true \
      -e KC_HOSTNAME_STRICT_HTTPS=false \
      quay.io/keycloak/keycloak:latest build
    
    # Run in production mode
    docker run \
      -p 8443:8443 \
      -e KC_DB=postgres \
      -e KC_DB_URL=jdbc:postgresql://postgres/keycloak \
      -e KC_DB_USERNAME=keycloak \
      -e KC_DB_PASSWORD=password \
      -e KEYCLOAK_ADMIN=admin \
      -e KEYCLOAK_ADMIN_PASSWORD=admin \
      -e KC_HOSTNAME=auth.example.com \
      -e KC_HTTPS_CERTIFICATE_FILE=/opt/keycloak/conf/server.crt \
      -e KC_HTTPS_CERTIFICATE_KEY_FILE=/opt/keycloak/conf/server.key \
      quay.io/keycloak/keycloak:latest start
    

    Realm Configuration

    Create Realm

    1. Login to admin console: http://localhost:8080/admin
    2. Click "Create Realm" (top-left dropdown)
    3. Enter realm name (e.g., "myapp")
    4. Click "Create"

    Realm Settings

    Realm Settings:
    - General
      - Display name: My Application
      - HTML Display name: <b>My App</b>
      - Frontend URL: https://auth.example.com (optional)
    
    - Login
      - User registration: Enable to allow self-registration
      - Edit username: Allow users to edit username
      - Forgot password: Enable password reset
      - Remember me: Allow remember me checkbox
      - Login with email: Allow email as username
    
    - Keys
      - Active keys for signing tokens
      - Configure providers (RSA, ECDSA, HMAC)
    
    - Email
      - From: noreply@example.com
      - Host: smtp.example.com
      - Port: 587
      - Enable authentication
      - Username/Password for SMTP
    
    - Themes
      - Login theme: keycloak (or custom)
      - Account theme: keycloak
      - Admin console theme: keycloak
      - Email theme: keycloak
    
    - Tokens
      - Access Token Lifespan: 5 minutes
      - Refresh Token Max Reuse: 0
      - SSO Session Idle: 30 minutes
      - SSO Session Max: 10 hours
    

    Client Configuration

    Create Client

    OpenID Connect Client:

    Client ID: my-app
    Client Protocol: openid-connect
    Root URL: http://localhost:3000
    
    Settings:
    - Client authentication: ON (for confidential clients)
    - Authorization: OFF (unless using fine-grained authz)
    - Valid redirect URIs:
      - http://localhost:3000/*
      - http://localhost:3000/api/auth/callback/keycloak
    - Valid post logout redirect URIs:
      - http://localhost:3000
    - Web origins: http://localhost:3000
    
    Capability config:
    - Client authentication: ON
    - Authorization: OFF
    - Standard flow: ON (Authorization Code Flow)
    - Direct access grants: ON (Resource Owner Password Credentials)
    - Implicit flow: OFF (deprecated)
    - Service accounts roles: ON (for client credentials)
    

    Client Credentials

    After creating client with authentication ON:

    1. Go to "Credentials" tab
    2. Copy "Client secret"
    3. Use in application configuration

    Client Scopes

    Create custom scope:
    1. Clients > Client scopes > Create
    2. Name: custom-scope
    3. Protocol: openid-connect
    4. Display on consent: OFF
    5. Include in token scope: ON
    
    Add mappers:
    1. Mappers tab > Create
    2. Mapper type: User Property
    3. Property: email
    4. Token Claim Name: email
    5. Claim JSON Type: String
    
    Assign to client:
    1. Clients > [your-client] > Client scopes
    2. Add available scope to Assigned default scopes
    

    User Management

    Create User

    Admin Console > Users > Create user
    
    Username: john.doe
    Email: john@example.com
    Email verified: ON
    First name: John
    Last name: Doe
    Enabled: ON
    
    Credentials:
    - Set password
    - Temporary: OFF (user won't be forced to change)
    

    User Attributes

    Users > [user] > Attributes
    
    Key: department
    Value: engineering
    
    Key: employee_id
    Value: EMP-12345
    

    User Roles

    1. Create roles:
       Realm roles > Create role
       - Name: admin
       - Name: user
       - Name: viewer
    
    2. Assign to user:
       Users > [user] > Role mapping
       - Assign role: admin
    

    User Groups

    1. Create group:
       Groups > Create group
       - Name: Developers
    
    2. Add attributes to group:
       Groups > Developers > Attributes
       - team: backend
    
    3. Assign roles to group:
       Groups > Developers > Role mapping
       - Assign: developer role
    
    4. Add users to group:
       Users > [user] > Groups
       - Join: Developers
    

    Roles & Permissions

    Realm Roles

    Realm roles > Create role
    
    Name: super-admin
    Description: Full system access
    
    Composite roles:
    - Add child roles (admin, user, viewer)
    

    Client Roles

    Clients > [client] > Roles > Create role
    
    Name: app-admin
    Description: Application administrator
    
    Use case: Application-specific roles
    

    Role Mappers

    Client scopes > roles > Mappers > realm roles
    
    Add to token:
    - Token Claim Name: realm_access.roles
    - Claim JSON Type: String
    - Add to ID token: ON
    - Add to access token: ON
    - Add to userinfo: ON
    

    Authentication Flows

    Browser Flow (Default)

    Authentication > Flows > Browser
    
    Steps:
    1. Cookie (SSO check)
    2. Kerberos (optional)
    3. Forms (username/password)
       - Username password form
       - OTP form (if enabled)
    

    Custom Authentication Flow

    1. Duplicate existing flow:
       Flows > Browser > Duplicate
    
    2. Customize:
       - Add execution
       - Set requirement (REQUIRED, ALTERNATIVE, DISABLED)
    
    3. Bind to client:
       Clients > [client] > Advanced > Authentication flow overrides
       - Browser flow: [custom-flow]
    

    Two-Factor Authentication

    1. Enable OTP:
       Authentication > Flows > Browser
       - Add execution: OTP Form
       - Requirement: CONDITIONAL
    
    2. Configure OTP:
       Authentication > OTP Policy
       - Type: Time-based or Counter-based
       - Algorithm: SHA1, SHA256, SHA512
       - Digits: 6
       - Period: 30 seconds
    
    3. Users enable OTP:
       Account console > Account security > Signing in
       - Set up Authenticator Application
    

    User Federation

    LDAP Integration

    User Federation > Add provider > LDAP
    
    Connection:
    - Console display name: LDAP
    - Edit mode: READ_ONLY or WRITEABLE
    - Sync registrations: ON
    - Vendor: Active Directory, Red Hat Directory Server, etc.
    - Connection URL: ldap://ldap.example.com:389
    - Users DN: ou=users,dc=example,dc=com
    - Bind DN: cn=admin,dc=example,dc=com
    - Bind credential: password
    
    LDAP searching and updating:
    - Custom user search filter: (objectClass=person)
    - Search scope: Subtree
    
    Synchronization:
    - Batch size: 1000
    - Full sync period: 604800 (weekly)
    - Changed users sync period: 86400 (daily)
    
    Test connection and authentication
    

    Custom User Storage SPI

    public class CustomUserStorageProvider implements UserStorageProvider {
        @Override
        public UserModel getUserById(String id, RealmModel realm) {
            // Fetch user from custom storage
        }
    
        @Override
        public UserModel getUserByUsername(String username, RealmModel realm) {
            // Lookup by username
        }
    
        @Override
        public UserModel getUserByEmail(String email, RealmModel realm) {
            // Lookup by email
        }
    }
    

    Identity Providers

    Social Login (Google)

    Identity Providers > Add provider > Google
    
    Settings:
    - Client ID: [from Google Console]
    - Client secret: [from Google Console]
    - Default scopes: openid profile email
    - Store tokens: ON
    - Stored tokens readable: ON
    
    Mappers:
    - Create mapper: Import from provider
    - Sync mode: Import or Force
    

    SAML Provider

    Identity Providers > Add provider > SAML
    
    Settings:
    - Service provider entity ID: my-app
    - Single sign-on service URL: [from SAML provider]
    - Name ID policy format: Email
    - Principal type: Subject NameID
    - Want AuthnRequests signed: ON
    
    Import from URL or file for metadata
    

    Token Configuration

    Access Token

    Clients > [client] > Settings > Advanced
    
    Access Token Lifespan: 5 minutes
    Client Session Idle: 30 minutes
    Client Session Max: 10 hours
    
    Include in token:
    - Standard claims (sub, aud, iss, exp, iat)
    - Custom claims via mappers
    

    Refresh Token

    Realm Settings > Tokens
    
    Refresh Token Max Reuse: 0
    Revoke Refresh Token: ON
    SSO Session Idle: 30 minutes
    SSO Session Max: 10 hours
    Offline Session Idle: 30 days
    

    Custom Claims

    Client scopes > [scope] > Mappers > Create
    
    Mapper type: User Attribute
    User attribute: department
    Token claim name: department
    Claim JSON Type: String
    Add to ID token: ON
    Add to access token: ON
    Add to userinfo: ON
    

    Admin API

    Get Admin Token

    # Password grant
    curl -X POST http://localhost:8080/realms/master/protocol/openid-connect/token \
      -d "client_id=admin-cli" \
      -d "username=admin" \
      -d "password=admin" \
      -d "grant_type=password"
    

    API Examples

    # Get realm
    curl -X GET http://localhost:8080/admin/realms/myapp \
      -H "Authorization: Bearer $TOKEN"
    
    # Create user
    curl -X POST http://localhost:8080/admin/realms/myapp/users \
      -H "Authorization: Bearer $TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
        "username": "john",
        "email": "john@example.com",
        "enabled": true,
        "firstName": "John",
        "lastName": "Doe"
      }'
    
    # Get users
    curl -X GET http://localhost:8080/admin/realms/myapp/users \
      -H "Authorization: Bearer $TOKEN"
    
    # Assign role
    curl -X POST http://localhost:8080/admin/realms/myapp/users/{userId}/role-mappings/realm \
      -H "Authorization: Bearer $TOKEN" \
      -H "Content-Type: application/json" \
      -d '[{"id": "{roleId}", "name": "admin"}]'
    

    Application Integration

    Next.js with NextAuth

    // pages/api/auth/[...nextauth].ts
    import NextAuth from "next-auth"
    import KeycloakProvider from "next-auth/providers/keycloak"
    
    export default NextAuth({
      providers: [
        KeycloakProvider({
          clientId: process.env.KEYCLOAK_CLIENT_ID!,
          clientSecret: process.env.KEYCLOAK_CLIENT_SECRET!,
          issuer: process.env.KEYCLOAK_ISSUER, // http://localhost:8080/realms/myapp
        }),
      ],
      callbacks: {
        async jwt({ token, account }) {
          if (account) {
            token.accessToken = account.access_token
            token.refreshToken = account.refresh_token
          }
          return token
        },
        async session({ session, token }) {
          session.accessToken = token.accessToken
          return session
        },
      },
    })
    
    // .env.local
    KEYCLOAK_CLIENT_ID=my-app
    KEYCLOAK_CLIENT_SECRET=secret
    KEYCLOAK_ISSUER=http://localhost:8080/realms/myapp
    

    Node.js with keycloak-connect

    const session = require('express-session')
    const Keycloak = require('keycloak-connect')
    
    const memoryStore = new session.MemoryStore()
    const keycloak = new Keycloak({ store: memoryStore }, {
      'realm': 'myapp',
      'auth-server-url': 'http://localhost:8080',
      'ssl-required': 'external',
      'resource': 'my-app',
      'credentials': {
        'secret': 'client-secret'
      }
    })
    
    app.use(session({
      secret: 'session-secret',
      resave: false,
      saveUninitialized: true,
      store: memoryStore
    }))
    
    app.use(keycloak.middleware())
    
    // Protected route
    app.get('/protected', keycloak.protect(), (req, res) => {
      res.json({ message: 'Protected resource' })
    })
    
    // Role-based protection
    app.get('/admin', keycloak.protect('admin'), (req, res) => {
      res.json({ message: 'Admin resource' })
    })
    

    React SPA

    import Keycloak from 'keycloak-js'
    
    const keycloak = new Keycloak({
      url: 'http://localhost:8080',
      realm: 'myapp',
      clientId: 'my-app',
    })
    
    // Initialize
    keycloak.init({
      onLoad: 'login-required',
      checkLoginIframe: false,
    }).then((authenticated) => {
      if (authenticated) {
        console.log('User is authenticated')
        console.log('Token:', keycloak.token)
        console.log('Roles:', keycloak.realmAccess?.roles)
      }
    })
    
    // Auto-refresh token
    keycloak.onTokenExpired = () => {
      keycloak.updateToken(30)
    }
    
    // API call with token
    fetch('/api/data', {
      headers: {
        'Authorization': `Bearer ${keycloak.token}`
      }
    })
    
    // Logout
    keycloak.logout({ redirectUri: 'http://localhost:3000' })
    
    // Check role
    if (keycloak.hasRealmRole('admin')) {
      // Show admin features
    }
    

    Security Best Practices

    1. Use HTTPS in production - Always enable SSL/TLS
    2. Strong client secrets - Use cryptographically random secrets
    3. Limit token lifetime - Short-lived access tokens (5-15 min)
    4. Refresh token rotation - Enable refresh token reuse detection
    5. PKCE for SPAs - Use Proof Key for Code Exchange
    6. Content Security Policy - Proper CSP headers
    7. Rate limiting - Protect against brute force
    8. Regular updates - Keep Keycloak up to date
    9. Audit logging - Enable and monitor event logs
    10. Role hierarchy - Use composite roles for complexity

    Troubleshooting

    Token Validation Issues

    # Decode JWT token
    echo $TOKEN | cut -d. -f2 | base64 -d | jq
    
    # Verify token signature
    curl http://localhost:8080/realms/myapp/protocol/openid-connect/certs
    

    Connection Issues

    # Check Keycloak health
    curl http://localhost:8080/health
    
    # Check realm endpoints
    curl http://localhost:8080/realms/myapp/.well-known/openid-configuration
    

    User Login Issues

    1. Check user is enabled
    2. Verify email is verified (if required)
    3. Check required actions (password reset, email verify)
    4. Review authentication logs (Events > Login Events)

    CORS Issues

    Clients > [client] > Settings
    - Web origins: http://localhost:3000
    - Valid redirect URIs: http://localhost:3000/*
    

    Common Tasks

    Export/Import Realm

    # Export realm
    docker exec keycloak /opt/keycloak/bin/kc.sh export \
      --dir /tmp/export \
      --realm myapp
    
    # Import realm
    docker exec keycloak /opt/keycloak/bin/kc.sh import \
      --file /tmp/export/myapp-realm.json
    

    Backup Database

    # PostgreSQL backup
    docker exec postgres pg_dump -U keycloak keycloak > keycloak-backup.sql
    
    # Restore
    docker exec -i postgres psql -U keycloak keycloak < keycloak-backup.sql
    

    Theme Customization

    themes/
    └── custom-theme/
        ├── login/
        │   ├── theme.properties
        │   ├── login.ftl
        │   └── resources/
        │       ├── css/
        │       └── img/
        └── account/
            └── ...
    
    Realm Settings > Themes > Login theme: custom-theme
    

    Resources

    • Docs: https://www.keycloak.org/documentation
    • Admin REST API: https://www.keycloak.org/docs-api/latest/rest-api/
    • Server Admin Guide: https://www.keycloak.org/docs/latest/server_admin/
    • GitHub: https://github.com/keycloak/keycloak
    Repository
    oriolrius/pki-manager-web
    Files