1. Authentication Flows — Tổng quan
Authentication Flow trong Keycloak là chuỗi các bước xác thực mà user phải trải qua khi đăng nhập, đăng ký, hoặc thực hiện các hành động bảo mật. Mỗi flow bao gồm các executions (authenticators) được sắp xếp theo thứ tự và có thể lồng nhau qua sub-flows.
Để xem và quản lý flows, vào Admin Console → Authentication → Flows.
1.1 Built-in Authentication Flows
Keycloak cung cấp sẵn các flows mặc định:
| Flow | Mô tả | Khi nào được trigger |
|---|---|---|
| Browser Flow | Luồng đăng nhập qua browser | User truy cập ứng dụng lần đầu hoặc session hết hạn |
| Direct Grant Flow | Xác thực trực tiếp bằng username/password (Resource Owner Password) | API call với grant_type=password |
| Registration Flow | Luồng đăng ký tài khoản mới | User click "Register" trên login page |
| Reset Credentials Flow | Luồng đặt lại mật khẩu | User click "Forgot Password" |
| First Broker Login Flow | Luồng xử lý lần đầu đăng nhập qua Identity Provider | User đăng nhập qua social login lần đầu |
| Docker Authentication Flow | Xác thực cho Docker registry | Docker client pull/push images |
| HTTP Challenge Flow | Xác thực qua HTTP headers | Non-browser clients (Kerberos, X.509) |
1.2 Flow Types
Mỗi flow có thể chứa các loại phần tử sau:
| Type | Mô tả |
|---|---|
| Authenticator | Một bước xác thực cụ thể (ví dụ: Username Password Form) |
| Sub-flow | Flow con chứa nhiều authenticators — cho phép tạo logic phức tạp |
| Form | Hiển thị form cho user nhập thông tin (username, password, OTP...) |
2. Browser Flow — Chi tiết
Browser Flow mặc định có cấu trúc như sau:
Browser Flow
├── Cookie (Alternative) → Kiểm tra SSO session cookie
├── Kerberos (Disabled) → Xác thực Kerberos (tắt mặc định)
├── Identity Provider Redirector (Alternative) → Redirect đến IdP nếu có
└── Forms (Alternative) → Sub-flow xử lý form login
├── Username Password Form (Required) → Nhập username + password
└── Browser - Conditional OTP (Conditional) → Sub-flow OTP
├── Condition - User Configured (Required) → Kiểm tra user đã setup OTP
└── OTP Form (Required) → Nhập mã OTP
Cách hoạt động:
- Cookie: Nếu user đã có session cookie hợp lệ → skip toàn bộ, đăng nhập thành công
- Kerberos: Disabled mặc định — nếu enabled sẽ thử Kerberos ticket
- Identity Provider Redirector: Nếu có
kc_idp_hint→ redirect đến IdP đó - Forms: Hiển thị login form
- Yêu cầu username + password
- Nếu user đã cấu hình OTP → yêu cầu nhập OTP code
2.1 Execution Requirements
Mỗi execution trong flow có một requirement xác định hành vi:
| Requirement | Mô tả | Khi nào sử dụng |
|---|---|---|
| Required | Bắt buộc phải thực hiện và thành công | Username/Password, OTP khi đã cấu hình |
| Alternative | Một trong các alternatives thành công là đủ | Cookie HOẶC Forms — chỉ cần 1 pass |
| Conditional | Sub-flow chỉ thực thi khi điều kiện đúng | Conditional OTP — chỉ yêu cầu OTP nếu user đã setup |
| Disabled | Bỏ qua hoàn toàn | Tạm tắt một bước mà không xóa |
Quy tắc quan trọng:
- Nếu tất cả executions trong flow là Alternative → chỉ cần 1 cái pass
- Nếu có ít nhất 1 Required → tất cả Required phải pass, Alternative bị bỏ qua
- Conditional thường dùng với sub-flow: bước đầu tiên là condition checker, các bước sau là authenticators
3. Tạo Custom Authentication Flow
Built-in flows không thể chỉnh sửa trực tiếp. Bạn cần duplicate rồi customise.
3.1 Duplicate và Chỉnh sửa
- Vào Authentication → Flows
- Chọn flow muốn copy, ví dụ
Browser - Click Action → Duplicate
- Đặt tên mới:
My Custom Browser Flow - Flow mới sẽ xuất hiện với toàn bộ executions giống bản gốc
3.2 Thêm Execution
Sau khi duplicate, bạn có thể thêm/xóa/sắp xếp lại executions:
- Trong custom flow, click "Add step"
- Chọn authenticator từ danh sách:
Username Password Form— Form nhập username + passwordOTP Form— Form nhập OTP codeCookie— Kiểm tra session cookieIdentity Provider Redirector— Redirect đến external IdPDeny Access— Từ chối truy cậpAllow Access— Cho phép truy cậpUsername Form— Chỉ nhập username (tách riêng password)Password Form— Chỉ nhập passwordWebAuthn Authenticator— Xác thực bằng security keyWebAuthn Passwordless Authenticator— Xác thực không mật khẩu
- Đặt requirement phù hợp (Required, Alternative, Conditional, Disabled)
3.3 Thêm Sub-flow
Sub-flow cho phép nhóm nhiều executions lại, tạo logic phức tạp hơn:
My Custom Browser Flow
├── Cookie (Alternative)
├── Identity Provider Redirector (Alternative)
└── My Login Forms (Alternative) ← Sub-flow
├── Username Password Form (Required)
└── MFA Sub-flow (Conditional) ← Sub-flow lồng nhau
├── Condition - User Configured (Required)
├── OTP Form (Alternative) ← Cho chọn OTP...
└── WebAuthn Authenticator (Alternative) ← ...hoặc Security Key
Cách thêm sub-flow:
- Click "Add sub-flow"
- Đặt tên, ví dụ:
MFA Sub-flow - Set requirement:
Conditional - Thêm executions vào sub-flow
4. Conditional Authenticators
Conditional authenticators cho phép kiểm tra điều kiện trước khi thực thi sub-flow. Nếu điều kiện không thoả → toàn bộ sub-flow bị bỏ qua.
4.1 Các Condition có sẵn
| Condition | Mô tả |
|---|---|
| Condition - User Configured | User đã cấu hình credential tương ứng (OTP, WebAuthn...) |
| Condition - User Role | User có role cụ thể |
| Condition - User Attribute | User có attribute cụ thể với giá trị mong muốn |
| Condition - Client Scope | Request có chứa scope cụ thể (ví dụ: acr_values) |
| Condition - Sub-flow Executed | Sub-flow trước đó đã được thực thi thành công |
4.2 Ví dụ: Conditional OTP theo Role
Yêu cầu OTP chỉ cho users có role admin:
My Custom Browser Flow
├── Cookie (Alternative)
└── Forms (Alternative)
├── Username Password Form (Required)
└── Admin OTP Sub-flow (Conditional)
├── Condition - User Role (Required) → Config: role = "admin"
└── OTP Form (Required)
Cấu hình Condition - User Role:
- Thêm
Condition - User Rolevào sub-flow - Click biểu tượng ⚙️ (Settings) bên cạnh condition
- Nhập:
- Alias:
Check Admin Role - User role:
admin(hoặcrealm-management.manage-userscho client role) - Negate output:
Off(On nếu muốn áp dụng cho user KHÔNG có role)
- Alias:
4.3 Condition - Client Scope
Yêu cầu MFA khi client request scope đặc biệt:
# Authorization request yêu cầu MFA
GET /realms/myrealm/protocol/openid-connect/auth?
client_id=my-app&
scope=openid profile mfa-required&
response_type=code&
redirect_uri=https://myapp.example.com/callback
My Custom Browser Flow
├── Cookie (Alternative)
└── Forms (Alternative)
├── Username Password Form (Required)
└── MFA When Requested (Conditional)
├── Condition - Client Scope (Required) → Config: scope = "mfa-required"
└── OTP Form (Required)
5. Step-up Authentication và Level of Authentication (LoA)
Step-up Authentication cho phép yêu cầu mức xác thực cao hơn cho các hành động nhạy cảm, mà không bắt user xác thực lại hoàn toàn.
5.1 ACR và LoA Mapping
ACR (Authentication Context Class Reference) là claim trong ID Token cho biết mức độ xác thực đã được thực hiện. Keycloak map ACR values sang Level of Authentication (LoA) — một số nguyên.
Cấu hình ACR to LoA mapping:
- Vào Authentication → Flows
- Mở flow đang sử dụng (ví dụ: Browser Flow)
- Mỗi sub-flow có thể gán một LoA level
My Step-up Browser Flow
├── Cookie (Alternative) → LoA: không set
└── Login Forms (Alternative)
├── Username Password Form (Required) → LoA Level 1
└── Step-up MFA (Conditional)
├── Condition - Level of Authentication (Required)
└── OTP Sub-flow (Conditional) → LoA Level 2
├── Condition - User Configured (Required)
└── OTP Form (Required)
Default LoA mapping (Authentication → Flows → gear icon):
# Trong Realm Settings → General → ACR to LoA Mapping:
# Hoặc cấu hình trong flow
{
"acr_to_loa_mapping": {
"urn:keycloak:loa:1": 1, // Password only
"urn:keycloak:loa:2": 2, // Password + OTP
"urn:keycloak:loa:3": 3, // Password + Security Key
"gold": 2, // Custom ACR value
"platinum": 3 // Custom ACR value
}
}
5.2 Request Step-up Authentication
Client yêu cầu LoA cụ thể qua acr_values hoặc claims parameter:
# Sử dụng acr_values (voluntary — không bắt buộc)
GET /realms/myrealm/protocol/openid-connect/auth?
client_id=my-app&
scope=openid&
acr_values=gold&
response_type=code&
redirect_uri=https://myapp.example.com/callback
# Sử dụng claims parameter (essential — bắt buộc LoA)
GET /realms/myrealm/protocol/openid-connect/auth?
client_id=my-app&
scope=openid&
claims={"id_token":{"acr":{"essential":true,"values":["gold"]}}}&
response_type=code&
redirect_uri=https://myapp.example.com/callback
Kết quả trong ID Token:
{
"acr": "gold",
"sub": "user-123",
"iss": "https://keycloak.example.com/realms/myrealm",
...
}
5.3 Kiểm tra LoA trong ứng dụng
// Spring Security — kiểm tra ACR level
@GetMapping("/sensitive-action")
public ResponseEntity<?> sensitiveAction(
@AuthenticationPrincipal OidcUser user) {
String acr = user.getIdToken().getClaimAsString("acr");
if (!"gold".equals(acr)) {
// Redirect user để step-up authentication
String stepUpUrl = keycloakBaseUrl +
"/realms/myrealm/protocol/openid-connect/auth" +
"?client_id=my-app" +
"&scope=openid" +
"&acr_values=gold" +
"&prompt=login" +
"&response_type=code" +
"&redirect_uri=" + redirectUri;
return ResponseEntity.status(302)
.header("Location", stepUpUrl)
.build();
}
return ResponseEntity.ok("Sensitive data here");
}
6. Direct Grant Flow
Direct Grant Flow xử lý grant_type=password — xác thực trực tiếp không qua browser:
Direct Grant Flow (mặc định)
├── Username Validation (Required) → Kiểm tra username tồn tại
├── Password (Required) → Verify password
└── Direct Grant - Conditional OTP (Conditional)
├── Condition - User Configured (Required)
└── OTP (Required)
# Ví dụ: Direct Grant request
curl -X POST \
https://keycloak.example.com/realms/myrealm/protocol/openid-connect/token \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'grant_type=password' \
-d 'client_id=my-backend' \
-d 'client_secret=my-secret' \
-d '[email protected]' \
-d 'password=user-password' \
-d 'totp=123456' # Nếu user đã setup OTP
⚠️ Lưu ý: Direct Grant (Resource Owner Password Credentials) không được khuyến khích trong production. Nên sử dụng Authorization Code Flow + PKCE thay thế.
7. Registration Flow
Registration Flow kiểm soát quá trình đăng ký tài khoản mới:
Registration Flow (mặc định)
└── Registration Form (Required)
├── Registration User Profile (Required) → Nhập thông tin profile
├── Password Validation (Required) → Nhập + confirm password
└── Recaptcha (Disabled) → reCAPTCHA (tắt mặc định)
7.1 Bật Registration
- Vào Realm Settings → Login
- Bật User registration: On
- Tuỳ chọn: Bật Email as username để user dùng email làm username
7.2 Custom Registration Flow
My Registration Flow
└── Registration Form (Required)
├── Registration User Profile (Required)
├── Password Validation (Required)
├── Recaptcha (Required) → Bật reCAPTCHA
└── Terms and Conditions (Required) → Yêu cầu đồng ý điều khoản
Cấu hình reCAPTCHA:
- Đăng ký Google reCAPTCHA v3 tại https://www.google.com/recaptcha/admin
- Trong flow, click ⚙️ bên cạnh
Recaptcha - Nhập:
- Recaptcha Site Key:
your-site-key - Recaptcha Secret:
your-secret-key - Use Recaptcha.net: On (nếu cần cho China)
- Recaptcha Site Key:
8. Reset Credentials Flow
Flow xử lý quá trình đặt lại mật khẩu:
Reset Credentials Flow (mặc định)
├── Choose User (Required) → User nhập username/email
├── Send Reset Email (Required) → Gửi email reset link
├── Reset Password (Required) → Form nhập mật khẩu mới
└── Reset - Conditional OTP (Conditional) → OTP nếu đã cấu hình
├── Condition - User Configured (Required)
└── Reset OTP (Required)
9. Session Limits
Keycloak cho phép giới hạn số lượng sessions đồng thời mỗi user.
9.1 Cấu hình Session Limits trong Authentication Flow
Thêm User Session Limits authenticator vào flow:
My Custom Browser Flow
├── Cookie (Alternative)
└── Forms (Alternative)
├── Username Password Form (Required)
├── Browser - Conditional OTP (Conditional)
│ ├── Condition - User Configured (Required)
│ └── OTP Form (Required)
└── User Session Limits (Required)
Cấu hình User Session Limits:
- Click ⚙️ bên cạnh
User Session Limits - Cấu hình:
- Max Realm Sessions: Tổng số sessions tối đa trong realm (ví dụ:
3) - Max Client Sessions: Số sessions tối đa cho 1 client (ví dụ:
1) - Behavior when limit reached:
Deny new session— Từ chối đăng nhập mớiTerminate oldest session— Đá session cũ nhất
- Error message: Custom message khi bị deny (ví dụ:
"Bạn đã đạt giới hạn phiên đăng nhập")
- Max Realm Sessions: Tổng số sessions tối đa trong realm (ví dụ:
10. Bind Flow vào Realm và Client
10.1 Bind Flow cho Realm
Sau khi tạo custom flow, bind nó làm flow mặc định cho realm:
- Vào Authentication → Flows
- Click tab "Bindings" (hoặc Required Actions)
- Chọn flow cho từng binding:
- Browser Flow:
My Custom Browser Flow - Direct Grant Flow:
Direct Grant - Registration Flow:
My Registration Flow - Reset Credentials Flow:
Reset Credentials
- Browser Flow:
10.2 Bind Flow cho Client cụ thể
Bạn có thể override realm flow cho từng client:
- Vào Clients → chọn client
- Tab "Advanced"
- Mục "Authentication Flow Overrides":
- Browser Flow: Chọn flow khác realm default
- Direct Grant Flow: Chọn flow khác
11. Dynamic Flow Selection với Client Policies
Từ Keycloak 25+, bạn có thể sử dụng Client Policies để tự động chọn authentication flow dựa trên client properties.
11.1 Tạo Client Policy cho Flow Selection
- Vào Realm Settings → Client Policies → Policies
- Tạo policy mới:
Secure Clients MFA Policy - Thêm Condition:
- Type:
client-scopes - Scopes:
["mfa-required"]
- Type:
- Thêm Profile (từ Client Profiles):
- Profile executor: override browser flow
// Client Policy — ví dụ export JSON
{
"policies": [
{
"name": "Secure Clients MFA Policy",
"description": "Enforce MFA for clients with mfa-required scope",
"enabled": true,
"conditions": [
{
"condition": "client-scopes",
"configuration": {
"scopes": ["mfa-required"],
"type": "DEFAULT"
}
}
],
"profiles": ["mfa-enforced-profile"]
}
]
}
12. Export/Import Authentication Flows
Authentication flows được bao gồm trong realm export:
# Export realm bao gồm flows
/opt/keycloak/bin/kc.sh export \
--dir /opt/keycloak/data/export \
--realm myrealm
# Trong file realm-export.json, flows nằm ở:
# "authenticationFlows": [...]
# "authenticationExecutions": [...]
Partial import via Admin REST API:
# Lấy danh sách flows
curl -s -X GET \
"https://keycloak.example.com/admin/realms/myrealm/authentication/flows" \
-H "Authorization: Bearer $ADMIN_TOKEN" | jq '.[].alias'
# Export 1 flow cụ thể
FLOW_ID=$(curl -s -X GET \
"https://keycloak.example.com/admin/realms/myrealm/authentication/flows" \
-H "Authorization: Bearer $ADMIN_TOKEN" | \
jq -r '.[] | select(.alias=="My Custom Browser Flow") | .id')
curl -s -X GET \
"https://keycloak.example.com/admin/realms/myrealm/authentication/flows/$FLOW_ID/executions" \
-H "Authorization: Bearer $ADMIN_TOKEN" | jq .
13. Tóm tắt
| Khái niệm | Mô tả |
|---|---|
| Authentication Flow | Chuỗi bước xác thực — có thể lồng nhau qua sub-flows |
| Execution Requirements | Required, Alternative, Conditional, Disabled |
| Conditional Authenticators | Kiểm tra điều kiện trước khi thực thi sub-flow |
| Step-up Authentication | Yêu cầu LoA cao hơn cho hành động nhạy cảm |
| ACR to LoA Mapping | Map ACR values sang numeric levels |
| Session Limits | Giới hạn concurrent sessions per user |
| Flow Binding | Bind flows ở realm level hoặc per-client override |