Keycloak là gì: realm, client, user, role

4 câu hỏi~25 phútTừ khóa: Identity Provider, realm, public client, confidential client, realm role, client role, group, client scope, identity brokering

Bắt đầu Keycloak nhé. Mình đã dùng nó ở phía Spring rồi, giờ muốn hiểu bản thân Keycloak.

Ở bài 4.4.8, Keycloak chỉ là "chỗ phát token" và các service Spring validate token đó. Chương này đứng ở phía bên kia: Keycloak là một Identity Provider (IdP) độc lập, không phải thư viện Spring. Nó là một server riêng (viết bằng Java, chạy trên Quarkus) mà bạn cài, cấu hình, vận hành. Khái niệm OAuth2/OIDC đã học ở 4.4.7, ở đây không nhắc lại.

1. Bài toán: shop-app có nhiều cửa đăng nhập

Project ví dụ của chương: shop-app.

shop-app/
├── web-spa/          (React, chạy trên trình duyệt)
├── mobile-app/       (Android/iOS)
├── admin-portal/     (cho nhân viên)
├── order-service/    (Spring Boot)
└── payment-service/  (Spring Boot)

Cách làm "tự nhiên" lúc đầu: mỗi app có màn login riêng, mỗi service có bảng users riêng hoặc dùng chung một bảng.

2. Vấn đề

3. Giải pháp: một Identity Provider tập trung

Mọi app không tự kiểm tra password. Chúng chuyển người dùng sang Keycloak, Keycloak xác thực rồi trả token. App chỉ tin token.

Các khái niệm cốt lõi của Keycloak:

Khái niệmLà gìTrong shop-app
RealmMột "không gian" cô lập: user, client, role, cấu hình login riêng. Realm master chỉ dùng để quản trị Keycloak.Realm shop
ClientMột ứng dụng được phép xin token từ realmshop-web, shop-mobile, shop-admin, order-service, payment-service
UserNgười đăng nhập, có username, email, credential, attributealice (khách), bob (nhân viên)
Realm roleRole dùng chung cả realmcustomer, staff
Client roleRole chỉ có nghĩa trong một clientorder-service: order:refund
GroupNhóm user, gán role cho cả nhóm/support-team
Client scopeBộ claim/mapper dùng lại cho nhiều client, gắn với scope trong requestprofile, email, shop-customer
Identity providerIdP ngoài mà Keycloak "nhờ" xác thực (brokering)Google, Azure AD của công ty

Public client và confidential client

Public clientConfidential client
Giữ được secret?Không (code chạy trên máy người dùng)Có (chạy trên server)
Ví dụshop-web (SPA), shop-mobileorder-service, backend của admin-portal
Bảo vệ bằngPKCE + redirect URI chặtClient secret hoặc private key JWT
Trong admin consoleClient authentication: OffClient authentication: On

4. Code từng bước: dựng mô hình realm shop

Bước 1: Thiết kế trên giấy trước khi click.

realm: shop
├── clients
│   ├── shop-web        (public, Standard flow + PKCE)
│   ├── shop-mobile     (public, Standard flow + PKCE)
│   ├── shop-admin      (confidential, Standard flow)
│   ├── order-service   (confidential, Service accounts)
│   └── payment-service (bearer-only về mặt ý nghĩa: chỉ nhận token)
├── realm roles: customer, staff
├── client roles
│   └── order-service: order:read, order:refund
├── groups
│   └── /support-team → staff, order-service:order:refund
└── identity providers: google

Bước 2: Tạo bằng admin CLI (chi tiết dựng server ở bài 12.2):

KCADM=/opt/keycloak/bin/kcadm.sh
$KCADM config credentials --server http://localhost:8080 \
  --realm master --user "$KC_ADMIN_USER" --password "$KC_ADMIN_PASSWORD"

$KCADM create realms -s realm=shop -s enabled=true
$KCADM create roles -r shop -s name=customer
$KCADM create roles -r shop -s name=staff
$KCADM create clients -r shop -s clientId=shop-web \
  -s publicClient=true -s standardFlowEnabled=true \
  -s 'redirectUris=["http://localhost:5173/*"]' \
  -s 'webOrigins=["http://localhost:5173"]' \
  -s 'attributes={"pkce.code.challenge.method":"S256"}'

Bước 3: Phía Java không có gì mới: service Spring trỏ issuer-uri tới realm.

spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          issuer-uri: ${KEYCLOAK_ISSUER:http://localhost:8080/realms/shop}

Keycloak 17+ không còn tiền tố /auth. URL realm là /realms/shop, không phải /auth/realms/shop.

Bước 4: Kiểm tra bằng curl

curl -s http://localhost:8080/realms/shop/.well-known/openid-configuration | jq '{issuer, authorization_endpoint, token_endpoint, jwks_uri}'

5. Cách hoạt động

             +-------------------- Keycloak ---------------------+
             |  realm master (chỉ admin Keycloak)                |
             |  realm shop                                       |
             |    users ── groups ── roles                       |
             |    clients ── client scopes ── mappers            |
             |    identity providers (Google, Azure AD)          |
             +---------------------------------------------------+
                  ^ login (redirect)         | token (JWT)
                  |                          v
  web-spa / mobile / admin-portal  ──Bearer──>  order-service ──> payment-service
                                                 (verify chữ ký bằng JWKS của realm shop)

Identity brokering nhìn tổng quan:

User ─> shop-web ─> Keycloak (realm shop) ─"Login with Google"─> Google
                         ^                                       |
                         +──────── id_token của Google ──────────+
Keycloak tạo/liên kết user nội bộ, rồi phát token CỦA REALM shop cho shop-web.

App chỉ biết một issuer duy nhất là Keycloak, dù user đăng nhập bằng Google hay Azure AD.

6. So sánh: tự làm login và dùng IdP

Tiêu chíMỗi service tự loginKeycloak
Nơi giữ passwordNhiều nơiMột nơi
SSOTự codeCó sẵn
MFA, quên mật khẩu, khóa tài khoảnTự codeBật trong admin console
Social login, LDAPSửa từng appCấu hình một lần
Chi phíCode + bug bảo mậtVận hành thêm một server stateful

7. Khi nào nên dùng / không nên dùng

Vậy mình tạo mỗi app một realm cho gọn được không? Realm shop-web, realm shop-admin…

Không nên. Bạn đang nhầm realm với client. Realm là ranh giới của tập user, client mới là ranh giới của ứng dụng.

SAI                                   ĐÚNG
realm shop-web    (alice)             realm shop
realm shop-mobile (alice lần 2)         ├── client shop-web
realm shop-admin  (bob)                 ├── client shop-mobile
                                        └── client shop-admin
→ alice có 2 tài khoản, không SSO     → alice một tài khoản, SSO giữa web và mobile

Khi nào tách realm thật sự? Khi tập user tách biệt hoàn toàn: ví dụ khách hàng (shop) và nhân viên nội bộ dùng Azure AD (staff), hoặc mỗi tenant B2B một realm. Nhưng nhiều realm (hàng trăm) làm Keycloak khởi động và admin console chậm, nên multi-tenant lớn thường dùng một realm + group/organization.

Role refund mình nên tạo là realm role hay client role của order-service? Nhìn thì cả hai đều chạy được.

Đúng là cả hai đều chạy. Khác nhau ở phạm vi ý nghĩa:

Realm roleClient role
Ý nghĩaNgười này là ai trong tổ chứcNgười này được làm gì trong một app
Ví dụcustomer, stafforder-service: order:refund
Trong tokenrealm_access.rolesresource_access.order-service.roles
Rủi roDễ phình thành danh sách rất dàiPhải map ở phía service

Với refund: chỉ order-service hiểu nó, nên là client role. Chi tiết composite role, group, mapper ở bài 12.4; cách Spring đọc resource_access đã có ở 4.4.8.

Phỏng vấn hỏi Keycloak là gì, realm và client khác gì thì trả lời sao?

Q1. Vì sao dùng Identity Provider như Keycloak thay vì mỗi service tự làm login?

🇻🇳 Tiếng Việt:

Để credential chỉ nằm ở một nơi và các app chỉ tin token. Keycloak lo login, MFA, quên mật khẩu, SSO, social login, LDAP. Service không chạm vào password, chỉ verify chữ ký JWT. Đổi lại phải vận hành thêm một server stateful.

🇬🇧 English:

So that credentials live in one place and applications only trust tokens. Keycloak handles login, MFA, password reset, SSO, social login and LDAP. Services never touch passwords; they only verify JWT signatures. The trade-off is operating one more stateful server.

Q2. Realm và client khác nhau thế nào?

🇻🇳 Tiếng Việt:

Realm là không gian cô lập chứa user, role, cấu hình login; SSO chỉ có trong một realm. Client là một ứng dụng được phép xin token từ realm. Một sản phẩm thường có một realm và nhiều client.

🇬🇧 English:

A realm is an isolated space with its own users, roles and login settings; SSO only works within a realm. A client is an application allowed to request tokens from that realm. One product usually has one realm and many clients.

Q3. Public client và confidential client khác nhau thế nào?

🇻🇳 Tiếng Việt:

Public client chạy trên máy người dùng như SPA, mobile, không giữ được secret nên dùng PKCE và redirect URI chặt. Confidential client chạy trên server, xác thực với Keycloak bằng client secret hoặc private key JWT.

🇬🇧 English:

A public client runs on the user's device, like a SPA or mobile app, and cannot keep a secret, so it relies on PKCE and strict redirect URIs. A confidential client runs on a server and authenticates to Keycloak with a client secret or a private key JWT.

Cách nhớ ngắn gọn


Tự kiểm tra

Realm master dùng để làm gì?

Chỉ để quản trị Keycloak (admin). User và client của ứng dụng nằm ở realm riêng như shop.

Vì sao SPA phải là public client?

Code SPA tải về trình duyệt, ai cũng đọc được, nên không giữ được secret. Bảo vệ bằng PKCE và redirect URI.

Tách web và mobile thành hai realm thì mất gì?

Mất SSO, user bị nhân đôi tài khoản, service phải tin hai issuer.

Client role nằm ở claim nào trong access token?

resource_access.<clientId>.roles. Realm role nằm ở realm_access.roles.

URL issuer của realm shop trên Keycloak 26 là gì?

http://host:8080/realms/shop, không còn /auth.