keycloak

安装量: 36
排名: #19335

安装

npx skills add https://github.com/oriolrius/pki-manager-web --skill keycloak

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 Login to admin console: http://localhost:8080/admin Click "Create Realm" (top-left dropdown) Enter realm name (e.g., "myapp") Click "Create" Realm Settings Realm Settings: - General - Display name: My Application - HTML Display name: My App - 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:

Go to "Credentials" tab Copy "Client secret" 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

  1. Assign to user: Users > [user] > Role mapping
  2. Assign role: admin

User Groups 1. Create group: Groups > Create group - Name: Developers

  1. Add attributes to group: Groups > Developers > Attributes
  2. team: backend

  3. Assign roles to group: Groups > Developers > Role mapping

  4. Assign: developer role

  5. Add users to group: Users > [user] > Groups

  6. 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

  1. Customize:
  2. Add execution
  3. Set requirement (REQUIRED, ALTERNATIVE, DISABLED)

  4. Bind to client: Clients > [client] > Advanced > Authentication flow overrides

  5. Browser flow: [custom-flow]

Two-Factor Authentication 1. Enable OTP: Authentication > Flows > Browser - Add execution: OTP Form - Requirement: CONDITIONAL

  1. Configure OTP: Authentication > OTP Policy
  2. Type: Time-based or Counter-based
  3. Algorithm: SHA1, SHA256, SHA512
  4. Digits: 6
  5. Period: 30 seconds

  6. Users enable OTP: Account console > Account security > Signing in

  7. 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 Use HTTPS in production - Always enable SSL/TLS Strong client secrets - Use cryptographically random secrets Limit token lifetime - Short-lived access tokens (5-15 min) Refresh token rotation - Enable refresh token reuse detection PKCE for SPAs - Use Proof Key for Code Exchange Content Security Policy - Proper CSP headers Rate limiting - Protect against brute force Regular updates - Keep Keycloak up to date Audit logging - Enable and monitor event logs 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 Check user is enabled Verify email is verified (if required) Check required actions (password reset, email verify) 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

返回排行榜