1. OTP Authentication — TOTP và HOTP
OTP (One-Time Password) là phương thức MFA phổ biến nhất. Keycloak hỗ trợ hai loại:
| Loại | Mô tả | Thuật toán |
|---|---|---|
| TOTP (Time-based) | Mã OTP thay đổi theo thời gian (mỗi 30s) | RFC 6238 |
| HOTP (HMAC-based) | Mã OTP thay đổi theo counter | RFC 4226 |
TOTP được khuyến khích vì bảo mật hơn — mã tự hết hạn theo thời gian. HOTP chỉ dùng khi thiết bị không hỗ trợ đồng hồ chính xác.
1.1 OTP Policy Configuration
Cấu hình OTP Policy tại Authentication → Policies → OTP Policy:
| Setting | Mô tả | Giá trị mặc định | Khuyến nghị |
|---|---|---|---|
| OTP Type | TOTP hoặc HOTP | totp | totp |
| OTP Hash Algorithm | Thuật toán hash | SHA1 | SHA256 hoặc SHA512 |
| Number of Digits | Số chữ số OTP | 6 | 6 (tương thích tốt nhất) |
| Look Ahead Window | Số mã trước/sau được chấp nhận | 1 | 1 — tăng nếu user hay bị lệch time |
| OTP Token Period | Thời gian sống mỗi mã (giây) — chỉ TOTP | 30 | 30 |
| Initial Counter | Counter khởi đầu — chỉ HOTP | 0 | 0 |
| Supported Applications | Apps hiển thị trong hướng dẫn setup | FreeOTP, Google Authenticator | Thêm các app khác nếu cần |
1.2 Setup OTP với Google Authenticator / FreeOTP
Bước 1: Bật OTP trong Authentication Flow
Mặc định, Browser Flow đã có Browser - Conditional OTP sub-flow. OTP chỉ yêu cầu khi user đã setup OTP credential. Để bắt buộc tất cả users phải setup OTP:
- Vào Authentication → Required Actions
- Tìm Configure OTP
- Bật Default Action: On — tất cả users mới phải setup OTP
- Hoặc bật Required ở column "Set as default action" để enforce cho existing users
Bước 2: User đăng ký OTP
Khi user đăng nhập lần đầu (hoặc sau khi admin bật Required Action):
- Keycloak hiển thị trang "Mobile Authenticator Setup"
- User mở app Google Authenticator hoặc FreeOTP
- Scan QR code hoặc nhập manual key
- Nhập mã OTP xác nhận từ app
- OTP credential được lưu cho user
Bước 3: Xác thực OTP
Từ lần đăng nhập tiếp theo, sau khi nhập username/password, user phải nhập mã OTP từ app.
1.3 Quản lý OTP Credentials
# Admin xem OTP credentials của user
curl -s -X GET \
"https://keycloak.example.com/admin/realms/myrealm/users/$USER_ID/credentials" \
-H "Authorization: Bearer $ADMIN_TOKEN" | \
jq '.[] | select(.type=="otp")'
# Admin xóa OTP credential (force user setup lại)
curl -X DELETE \
"https://keycloak.example.com/admin/realms/myrealm/users/$USER_ID/credentials/$CREDENTIAL_ID" \
-H "Authorization: Bearer $ADMIN_TOKEN"
# Admin trigger Required Action cho user cụ thể
curl -X PUT \
"https://keycloak.example.com/admin/realms/myrealm/users/$USER_ID" \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"requiredActions": ["CONFIGURE_TOTP"]
}'
2. Recovery Codes
Recovery Codes cho phép user khôi phục truy cập khi mất thiết bị OTP.
2.1 Bật Recovery Codes
- Vào Authentication → Required Actions
- Tìm Recovery Authentication Codes (nếu chưa có, cần register)
- Bật Default Action hoặc Enabled
Enforce Recovery Codes sau OTP setup:
Để bắt buộc user tạo recovery codes ngay sau khi setup OTP, cấu hình Required Actions theo thứ tự:
CONFIGURE_TOTP— Setup OTP trướcCONFIGURE_RECOVERY_AUTHN_CODES— Tạo recovery codes sau
2.2 Sử dụng Recovery Codes
Khi user mất thiết bị OTP:
- Tại màn hình nhập OTP, click "Try another way"
- Chọn "Recovery Code"
- Nhập 1 trong các recovery codes đã lưu
- Mỗi code chỉ dùng được 1 lần
- Sau khi dùng hết codes, cần generate lại
3. WebAuthn (FIDO2) — Security Keys
WebAuthn cho phép xác thực bằng hardware security keys (YubiKey, Google Titan) hoặc platform authenticators (Touch ID, Windows Hello).
3.1 Setup WebAuthn trong Browser Flow
Bước 1: Thêm WebAuthn vào Authentication Flow
- Duplicate Browser Flow →
Browser with WebAuthn - Trong sub-flow Forms, thêm
WebAuthn Authenticator - Cấu trúc flow:
Browser with WebAuthn ├── Cookie (Alternative) └── Forms (Alternative) ├── Username Password Form (Required) └── WebAuthn MFA (Conditional) ├── Condition - User Configured (Required) └── WebAuthn Authenticator (Required) - Bind flow: Authentication → Bindings → Browser Flow = Browser with WebAuthn
Bước 2: Bật Required Action
- Vào Authentication → Required Actions
- Tìm WebAuthn Register → bật Default Action
- Users mới sẽ được yêu cầu đăng ký security key
3.2 WebAuthn Policy Configuration
Cấu hình tại Authentication → Policies → WebAuthn Policy:
| Setting | Mô tả | Giá trị |
|---|---|---|
| Relying Party Entity Name | Tên hiển thị cho user | Keycloak hoặc tên công ty |
| Signature Algorithms | Thuật toán chữ ký | ES256 (khuyến nghị), RS256 |
| Relying Party ID | Domain của Keycloak | keycloak.example.com (hoặc để trống = auto) |
| Attestation Conveyance Preference | Yêu cầu attestation từ key | not specified hoặc direct |
| Authenticator Attachment | Loại authenticator | not specified (chấp nhận cả USB key và platform) |
| Require Resident Key | Key phải lưu trên device | not specified |
| User Verification Requirement | Yêu cầu xác thực user trên device | not specified hoặc required |
| Create Timeout | Timeout khi đăng ký key (giây) | 0 (không timeout) |
| Avoid Same Authenticator Register | Không cho đăng ký cùng key 2 lần | Off |
| Acceptable AAGUIDs | Whitelist security key models | Để trống = chấp nhận tất cả |
3.3 Quản lý WebAuthn Credentials
# Xem WebAuthn credentials của user
curl -s -X GET \
"https://keycloak.example.com/admin/realms/myrealm/users/$USER_ID/credentials" \
-H "Authorization: Bearer $ADMIN_TOKEN" | \
jq '.[] | select(.type=="webauthn")'
# Response
{
"id": "credential-uuid",
"type": "webauthn",
"userLabel": "YubiKey 5",
"createdDate": 1711900000000,
"credentialData": "{\"aaguid\":\"...\",\"credentialPublicKey\":\"...\"}"
}
User cũng có thể tự quản lý security keys trong Account Console tại /realms/myrealm/account/#/security/webauthn.
4. Passkeys
Passkeys là phát triển tiếp theo của WebAuthn — cho phép đăng nhập không mật khẩu (passwordless) bằng fingerprint, face recognition, hoặc device PIN.
4.1 Passkeys vs WebAuthn truyền thống
| Tính năng | WebAuthn (MFA) | Passkeys (Passwordless) |
|---|---|---|
| Mục đích | MFA — thêm bước sau password | Thay thế password hoàn toàn |
| Authenticator | WebAuthn Authenticator | WebAuthn Passwordless Authenticator |
| Policy | WebAuthn Policy | WebAuthn Passwordless Policy |
| Required Action | WebAuthn Register | WebAuthn Register Passwordless |
| Resident Key | Không bắt buộc | Bắt buộc (discoverable credential) |
| User Verification | Tuỳ chọn | Required (biometrics/PIN) |
4.2 Bật Passkeys
Bước 1: Cấu hình WebAuthn Passwordless Policy
- Vào Authentication → Policies → WebAuthn Passwordless Policy
- Cấu hình:
- Relying Party Entity Name:
My Company - Signature Algorithms:
ES256 - User Verification Requirement:
required - Require Resident Key:
Yes— bắt buộc cho Passkeys
- Relying Party Entity Name:
Bước 2: Tạo Passwordless Browser Flow
Passwordless Browser Flow
├── Cookie (Alternative)
└── Passwordless Login (Alternative)
├── WebAuthn Passwordless Authenticator (Alternative) → Đăng nhập bằng Passkey
└── Username Password Fallback (Alternative) → Sub-flow fallback
├── Username Password Form (Required)
└── Conditional OTP (Conditional)
├── Condition - User Configured (Required)
└── OTP Form (Required)
Bước 3: Bật Required Action
- Vào Authentication → Required Actions
- Bật WebAuthn Register Passwordless → Default Action: On
4.3 Passkey UI Modes — Conditional và Modal
Conditional UI (Autofill):
Passkey gợi ý tự động trong trường username — user chỉ cần chọn và xác thực bằng biometrics. Đây là trải nghiệm mượt nhất.
Để bật Conditional UI, đặt WebAuthn Passwordless Authenticator ở vị trí đầu tiên trong flow với requirement Alternative.
Modal UI:
Browser hiển thị dialog yêu cầu xác thực bằng Passkey. User phải tương tác với dialog. Dùng khi muốn explicit UX.
4.4 Đăng ký Passkey qua AIA (Application Initiated Action)
User có thể đăng ký Passkey bất kỳ lúc nào qua AIA link:
# AIA URL để trigger Passkey registration
GET /realms/myrealm/protocol/openid-connect/auth?
client_id=my-app&
redirect_uri=https://myapp.example.com/callback&
response_type=code&
scope=openid&
kc_action=webauthn-register-passwordless
Skip if exists: Nếu muốn skip registration khi user đã có Passkey:
# Thêm parameter skip_if_exists
GET /realms/myrealm/protocol/openid-connect/auth?
client_id=my-app&
redirect_uri=https://myapp.example.com/callback&
response_type=code&
scope=openid&
kc_action=webauthn-register-passwordless&
kc_action_parameter=skip_if_exists
JavaScript integration:
// Sử dụng keycloak-js adapter
const keycloak = new Keycloak({
url: 'https://keycloak.example.com',
realm: 'myrealm',
clientId: 'my-app'
});
// Trigger Passkey registration
function registerPasskey() {
keycloak.login({
action: 'webauthn-register-passwordless'
});
}
// Button trong UI
document.getElementById('registerPasskeyBtn')
.addEventListener('click', registerPasskey);
5. Kerberos Authentication
Kerberos cho phép Single Sign-On tự động cho users đã đăng nhập vào domain (Windows AD, MIT Kerberos). User không cần nhập credentials — browser tự gửi Kerberos ticket.
5.1 Kerberos Server Setup
Yêu cầu:
- KDC (Key Distribution Center) đang chạy — Active Directory hoặc MIT Kerberos
- SPN (Service Principal Number) cho Keycloak service
- Keytab file cho Keycloak
# Tạo SPN và keytab cho Keycloak (MIT Kerberos)
kadmin -q "addprinc -randkey HTTP/[email protected]"
kadmin -q "ktadd -k /etc/keycloak/keycloak.keytab HTTP/[email protected]"
# Đặt permission
chmod 600 /etc/keycloak/keycloak.keytab
chown keycloak:keycloak /etc/keycloak/keycloak.keytab
5.2 Cấu hình Keycloak cho Kerberos
Option 1: Kerberos User Storage Provider
- Vào User Federation → Add provider → Kerberos
- Cấu hình:
- Kerberos Realm:
EXAMPLE.COM - Server Principal:
HTTP/[email protected] - Key Tab:
/etc/keycloak/keycloak.keytab - Allow Kerberos Authentication: On
- Use Kerberos For Password Authentication: On
- Update First Login: On
- Kerberos Realm:
Option 2: LDAP + Kerberos (Active Directory)
- Vào User Federation → Add provider → LDAP
- Cấu hình LDAP connection cho AD
- Bật mục Allow Kerberos Authentication
- Nhập Kerberos Realm, Server Principal, Key Tab
5.3 Bật Kerberos trong Browser Flow
- Vào Authentication → Flows → Browser (hoặc custom flow)
- Tìm Kerberos execution
- Đổi requirement từ
DisabledsangAlternative
Browser Flow (Kerberos enabled)
├── Cookie (Alternative)
├── Kerberos (Alternative) ← BẬT lên
├── Identity Provider Redirector (Alternative)
└── Forms (Alternative)
├── Username Password Form (Required)
└── Browser - Conditional OTP (Conditional)
├── Condition - User Configured (Required)
└── OTP Form (Required)
5.4 Cross-realm Trust
Cho phép users từ một Kerberos realm tin tưởng realm khác:
# /etc/krb5.conf trên Keycloak server
[libdefaults]
default_realm = CORP.EXAMPLE.COM
dns_lookup_realm = false
dns_lookup_kdc = false
[realms]
CORP.EXAMPLE.COM = {
kdc = dc1.corp.example.com
admin_server = dc1.corp.example.com
}
PARTNER.EXAMPLE.COM = {
kdc = kdc.partner.example.com
}
[capaths]
PARTNER.EXAMPLE.COM = {
CORP.EXAMPLE.COM = .
}
6. X.509 Client Certificate Authentication
X.509 cho phép xác thực bằng client certificate — phổ biến trong môi trường enterprise, government, hoặc mTLS.
6.1 Thêm X.509 vào Browser Flow
- Duplicate Browser Flow →
Browser with X.509 - Thêm
X509/Validate Username Formvào flow
Browser with X.509
├── Cookie (Alternative)
├── X509/Validate Username Form (Alternative) ← Thêm mới
├── Identity Provider Redirector (Alternative)
└── Forms (Alternative)
├── Username Password Form (Required)
└── Browser - Conditional OTP (Conditional)
├── Condition - User Configured (Required)
└── OTP Form (Required)
6.2 Cấu hình X.509 Authenticator
Click ⚙️ bên cạnh X509/Validate Username Form:
| Setting | Mô tả | Ví dụ |
|---|---|---|
| User Identity Source | Trường trong certificate để identify user | Subject's Common Name, Subject's e-mail |
| Mapping Source to User Attribute | Map identity source sang user attribute | Username or Email |
| A regular expression | Regex extract identity từ cert field | CN=(.*?)(?:,\|$) |
| CRL Checking Enabled | Kiểm tra Certificate Revocation List | On |
| CRL Distribution Point | URL hoặc path đến CRL | ldap://ca.example.com/CN=... |
| OCSP Checking Enabled | Kiểm tra Online Certificate Status Protocol | On |
| OCSP Responder URI | OCSP responder URL | http://ocsp.example.com |
| Certificate Key Usage | Key usage bắt buộc | digitalSignature |
| Certificate Extended Key Usage | Extended key usage | clientAuth |
| Certificate Policy Validation Mode | Validate certificate policies | Not Specified |
6.3 Certificate Mapping Strategies
Có nhiều cách map certificate sang Keycloak user:
# 1. Subject's Common Name → Username
# Certificate: CN=john.doe, OU=Engineering, O=Example Corp
# → username: john.doe
# 2. Subject's e-mail → Email
# Certificate: [email protected]
# → email: [email protected]
# 3. Serial Number → User Attribute
# Certificate: Serial=1A2B3C4D
# → user attribute "x509_serial" = "1A2B3C4D"
# 4. SHA-256 Certificate Thumbprint → User Attribute
# Certificate SHA-256: ab:cd:ef:12:34:...
# → user attribute "x509_thumbprint" = "ab:cd:ef:12:34:..."
# 5. Subject's DN với regex
# Certificate: CN=john.doe, OU=Engineering, O=Example Corp, C=VN
# Regex: CN=(.*?)(?:,|$)
# → Extracted: john.doe
6.4 CRL và OCSP Checking
Để đảm bảo certificates chưa bị thu hồi (revoked):
CRL (Certificate Revocation List):
- Keycloak download và cache CRL từ configured URI
- Kiểm tra serial number của client cert có trong CRL không
- Nếu CRL không available và
CRL Checking Enabled=On→ xác thực fail
OCSP (Online Certificate Status Protocol):
- Real-time check trạng thái certificate
- Keycloak gửi request đến OCSP Responder
- Nhanh hơn CRL cho individual checks
- Nhược điểm: phụ thuộc OCSP server availability
# Test OCSP check
openssl ocsp \
-issuer ca.pem \
-cert client.pem \
-url http://ocsp.example.com \
-resp_text
# Test certificate info
openssl x509 -in client.pem -noout -subject -serial -fingerprint -sha256
6.5 Keycloak mTLS Setup
Để Keycloak nhận client certificates, cần cấu hình reverse proxy hoặc Keycloak trực tiếp:
# Docker Compose — Keycloak với mTLS qua nginx
services:
nginx:
image: nginx:latest
ports:
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf
- ./certs/server.crt:/etc/nginx/certs/server.crt
- ./certs/server.key:/etc/nginx/certs/server.key
- ./certs/ca.crt:/etc/nginx/certs/ca.crt
depends_on:
- keycloak
keycloak:
image: quay.io/keycloak/keycloak:26.0
command: start --proxy-headers xforwarded
environment:
KC_HOSTNAME: keycloak.example.com
KC_HTTP_ENABLED: "true"
KC_PROXY_HEADERS: xforwarded
KEYCLOAK_ADMIN: admin
KEYCLOAK_ADMIN_PASSWORD: admin
# nginx.conf — Forward client certificate
server {
listen 443 ssl;
server_name keycloak.example.com;
ssl_certificate /etc/nginx/certs/server.crt;
ssl_certificate_key /etc/nginx/certs/server.key;
ssl_client_certificate /etc/nginx/certs/ca.crt;
ssl_verify_client optional;
location / {
proxy_pass http://keycloak:8080;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Port 443;
# Forward client certificate
proxy_set_header ssl-client-cert $ssl_client_escaped_cert;
}
}
7. So sánh các phương thức MFA
| Phương thức | Bảo mật | UX | Phishing-resistant | Use case |
|---|---|---|---|---|
| TOTP/HOTP | Trung bình | Tốt | Không | Phổ biến, dễ deploy |
| WebAuthn (MFA) | Cao | Tốt | Có | Enterprise, compliance |
| Passkeys | Rất cao | Xuất sắc | Có | Consumer + Enterprise |
| Kerberos | Cao | Xuất sắc (transparent) | Có (domain) | Enterprise, Windows domain |
| X.509 Certificate | Rất cao | Transparent | Có | Government, military, banking |
8. Tóm tắt
| Khái niệm | Mô tả |
|---|---|
| OTP Policy | TOTP/HOTP config — algorithm, digits, period, look ahead |
| Recovery Codes | Backup codes khi mất thiết bị OTP |
| WebAuthn | FIDO2 security keys — phishing-resistant MFA |
| Passkeys | Passwordless authentication — discoverable credentials + biometrics |
| Kerberos | Transparent SSO cho domain users |
| X.509 | Client certificate authentication — mTLS |
| CRL/OCSP | Certificate revocation checking |