์ฐธ๊ณ ์๋ฃ
* ์ฑ : https://www.yes24.com/Product/Goods/122459785
* ํ ์คํธ ์์ค์ฝ๋: https://github.com/PacktPublishing/Keycloak---Identity-and-Access-Management-for-Modern-Applications-2nd-Edition
์ค์ต ์ค๋น) Keycloak & ํ ์คํธ ์ ํ๋ฆฌ์ผ์ด์ ์ธํ
Keycloak์ ๋ก์ปฌ์์ ๋จผ์ ์คํํ๋ค.
docker run -p 8080:8080 \
-e KEYCLOAK_ADMIN=admin \
-e KEYCLOAK_ADMIN_PASSWORD=admin \
quay.io/keycloak/keycloak \
start-dev
์ดํ ํ ์คํธ ์ฝ๋ ์ดํ๋ฆฌ์ผ์ด์ ์ ์คํํ๋ค.
git clone https://github.com/PacktPublishing/Keycloak---Identity-and-Access-Management-for-Modern-Applications-2nd-Edition.git
cd Keycloak---Identity-and-Access-Management-for-Modern-Applications-2nd-Edition/ch4
npm install
npm start
์ค์ต #1) OIDC Discovery Endpoint ํ์ธ
*[์ฐธ๊ณ ]OpenID Connect๋ก ๋ณด์ ์ ํ๋ฆฌ์ผ์ด์ ๋ฐ ์๋น์ค
์ค์ตํด๋ณด๊ธฐ
ํ ์คํธ ํ์ด์ง (http://localhost:8000)์ ์ ์ํ๋ค.
'1 - Discovery' ํด๋ฆญ ๋ฐ ์ฌ๋ฐ๋ฅธ Issuer๋ฅผ ์
๋ ฅ ํ Load OpenID Provider Configuration์ ํด๋ฆญํ๋ค.
๊ทธ๋ผ ์๋ ์บก์ณ์ฌ์ง์ฒ๋ผ ๋ฉํ๋ฐ์ดํฐ๊ฐ ์ถ๋ ฅ๋๋ค.
์ด ๋ฉํ๋ฐ์ดํฐ๋ค์ Well-Known ์ค์ ์๋ํฌ์ธํธ (๊ฒ์(discovery)์๋ํฌ์ธํธ)์ด๋ฉฐ,
OpenID Provider(OP)์ ์ค์ ์ ๋ณด๋ฅผ ์๋์ผ๋ก ์ฐพ์ ์ ์๊ฒ ํด์ฃผ๋ ํ์คํ๋ ์๋ํฌ์ธํธ์ด๋ค.
์ฃผ์ ๋ฉํ๋ฐ์ดํฐ ์๋ฏธ
์๋ ํ๋ ์ฃผ์ ๋ฉํ๋ฐ์ดํฐ์ ๋ํ ์๋ฏธ๋ฅผ ์ค๋ช ํ๊ณ ์๋ค.
๊ตฌ๋ถ | ์ค๋ช |
issuer | OpenID Provider์ ์๋ณ์ URL |
authorization_endpoint | OpenID Provider์ ์๋ณ์ URL (์ธ์ฆ์์ฒญ) |
token_endpoint | ํ ํฐ์ ๋ฐ๊ธ๋ฐ๋ URL (ํ ํฐ์์ฒญ) |
introspection_endpoint | ์ก์ธ์ค ํ ํฐ์ด๋ ๋ฆฌํ๋ ์ ํ ํฐ์ ์ ํจ์ฑ์ ํ์ธํ๋ URL (์ ๊ฒ์์ฒญ) |
userinfo_endpoint | ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ค๋ URL (UserInfo์์ฒญ) |
end_session_endpoint | ๋ก๊ทธ์์์ ์ฒ๋ฆฌํ๋ URL |
jwks_uri | ๊ณต๊ฐ ํค๋ฅผ ์ ๊ณตํ๋ URL |
grant_types_supported | ์ง์ํ๋ ์ธ์ฆ ๋ฐฉ์(์: authorization_code, client_credentials ๋ฑ) |
response_types_supported | ํด๋ผ์ด์ธํธ๊ฐ ์์ฒญ ์ ์ฌ์ฉํ ์ ์๋ ์๋ต ํ์(์: code, token, id_token ๋ฑ) |
OIDC discovery endpoint ํ์ค spec
OpenID Connect Discovery 1.0 ์คํ์ OpenID Foundation์์ ๊ด๋ฆฌํ๊ณ ์๋ค.
- ๊ณต์ ์คํ ๋ฌธ์: OpenID Connect Discovery 1.0
- ๊ธฐํ ๊ด๋ จ ๋งํฌ๋ค:
Discovery endpoint์ ํ์ค ๊ฒฝ๋ก๋ ์๋์ ๊ฐ๋ค.
http://{keycloak domain}/realms/{realm-name}/.well-known/openid-configuration
#http://localhost:8080/realms/myrealm/.well-known/openid-configuration
์ค์ต #2) Authorization Code(์ธ๊ฐ์ฝ๋) ๋ฐ๊ธ๊ณผ์
Authentication ํ๋ ํ์ธ
๋จผ์ keycloak์์๋ oidc-playground ๋ผ๋ ํด๋ผ์ด์ธํธ๋ฅผ ์์ฑํ๋ค. (realm -> clients -> client์์ฑ)
๋ํ ์ฌ์ฉ์๋ ์์ฑํด์ผํ๋ค.
ํ
์คํธ ์ ์ ๋ ์์ ID๋ก ์์ฑํ ํ (์ฌ๊ธฐ์์๋ user01๋ก ์์ฑํ๋ค), Credentialsํญ์์ ๋น๋ฐ๋ฒํธ๋ฅผ ์ค์ ํ๋ค.
์ดํ ํ ์คํธ ํ์ด์ง (http://localhost:8000)์์ 2 - Authentication๋ฅผ ํด๋ฆญํ๋ค.
์ฌ๋ฐ๋ฅธ ๊ฐ์ ์ ๋ ฅ(์๋ ์ฐธ๊ณ )ํ๊ณ Generate Authentication Request๋ฅผ ํด๋ฆญํ์ฌ ์ธ์ฆ์์ฒญ์ด ์ด๋ป๊ฒ ์์ฑ๋๋์ง ํ์ธํ๋ค.
์ฒซ๋ฒ์งธ ํ์๋ฐ์ค Authentication์์์ ๊ฐ ํ๋๋ ์คํฌ๋ฆฐ์ท ๋ด์ฉ ํน์ ์๋ ๋ด์ฉ์ ์ฐธ๊ณ ํ๋ค.
- client_id: keycloak์์ ์์ฑํ client id
- scope:
- ํด๋ผ์ด์ธํธ๊ฐ ์ฌ์ฉ์์ ์ด๋ค ์ ๋ณด๋ ๋ฆฌ์์ค์ ์ ๊ทผํ๊ณ ์ถ์์ง ๋ํ๋ด๋ ๊ถํ ๋ฒ์
- openid๋ ๊ธฐ๋ณธ๊ฐ์ด๋ฉฐ, ๊ทธ ์ธ์๋ profile, email, phone, address ๋ฑ ์ฌ์ฉ ๊ฐ๋ฅ
- prompt: ์ฌ์ฉ์ ์ธ์ฆ ์ ํน์ ๋์์ ๊ฐ์ ํ๋ ํ๋ผ๋ฏธํฐ
- none: ์ด๋ฏธ ๋ก๊ทธ์ธ ๋ ๊ฒฝ์ฐ ์ฌ์ฉ์ ์ํธ์์ฉ ์์ด ์งํ
- login: ๊ฐ์ ๋ก ๋ค์ ๋ก๊ทธ์ธํ๋๋ก ํจ
- consent: ๊ถํ ๋ฑ์ ํ๋ฉด์ ๊ฐ์ ๋ก ๋ณด์ฌ์ค
- select_account: ๊ณ์ ์ ํ ํ๋ฉด์ ๋ณด์ฌ์ค
- max_age: ๋ก๊ทธ์ธ ์ธ์ ์ ์ต๋ ํ์ฉ ์๊ฐ(์ด)
- login_hint: ๋ก๊ทธ์ธ ํ์ด์ง์์ ์ฌ์ฉ์ ID๋ฅผ ๋ฏธ๋ฆฌ ์ฑ์๋ฃ์ ๋ ์ฌ์ฉ
- ์๋ฅผ๋ค์ด user01์ ์ ๋ ฅํด๋๋ฉด, ์ฌ์ฉ์ ๋ก๊ทธ์ธ์ ๋ฏธ๋ฆฌ user01์ด ์ฑ์์ ธ์๋ค.
- ์ฌ์ฉ์ ํธ์์ฑ์ ์ํด ์ฌ์ฉํ๋ค.
Authentication Request ํ์ธ
์ด๋ฒ ๋จ๊ณ์์๋ ์ค์ Authentication Request๊ฐ ์ด๋ป๊ฒ ์๊ฒผ๋์ง(?) ํ์ธํ ์ ์๋ค.
Authentication Response ํ์ธ
์ ์์ฒญ์ด ์ฒ๋ฆฌ๋๋ฉด Authentication Response๋ฅผ ๋ฐ๊ฒ ๋๋ค.
์๋ต์ผ๋ก ๋ฐ์ ์ฝ๋๋ IDํ ํฐ๊ณผ ๋ฆฌํ๋ ์ ํ ํฐ์ ์ป๊ธฐ์ํด ์ฌ์ฉํ๋ ์ธ๊ฐ์ฝ๋(Authorization Code)์ด๋ค.
๐ก ์ฌ๊ธฐ์ ๊ถ๊ธํ๋ถ๋ถ -์ธ์ฆ์ฝ๋๋ผ๊ณ ํ์ง ์๊ณ ์ธ๊ฐ์ฝ๋๋ผ๊ณ ์ผ์๊น? |
์ธ์ฆ๊ณผ ์ธ๊ฐ๋ ์ฌ์ ์ ์ ์๋ก ๋ณด์๋ฉด ์๋์ ๊ฐ๋ค. - ์ธ์ฆ(Authentication): "์ด ์ฌ๋์ด user01์ด ๋ง๋ค" - ์ธ๊ฐ(Authorization): "user01์ ์ด ํ์ผ์ ์ฝ์ ์ ์๋ค" OIDC๋ OAuth 2.0์์ ๊ตฌ์ถ๋์ด์์ด ์ฌ์ฉ์๋ฅผ ์ธ์ฆํ๋ฉด์ ์ดํ๋ฆฌ์ผ์ด์ ์ ๋ํ ๊ถํ๋ ๋ฐ๊ธ๋ฐ๊ฒ ๋๋ค. ์ฌ์ฉ์์ธ์ฆ->๊ถํ๋ถ์ฌ ๊ณผ์ ์ด ํ๋ฒ์ ์ฐ์์ ์ผ๋ก ์ผ์ด๋๋ฉฐ, ์ด๋ฒ ๋จ๊ณ์์๋ ์ธ์ฆ ํ๋ฆ ์ค ์ธ๊ฐ์ฝ๋๋ฅผ ๋ฐ๊ธ๋ฐ๋ ๋ถ๋ถ์ด๋ค. โโโโโ โโโโโ โโโโโ โโโโโโ โโโโโโ
โ ์ฌ์ฉ์ โ -> โ ์ธ์ฆ โ -> โ ์ธ๊ฐ โ -> โ Token โ -> โ Token โ
โ ๋ก๊ทธ์ธ โ โ ์ฑ๊ณต โ โ ์ฝ๋ โ โ ์์ฒญ โ โ ๋ฐ๊ธ โ
โโโโโ โโโโโ โโโโโ โโโโโโ โโโโฌโโ
(์ง๊ธ์ฌ๊ธฐ) ↓
โโโโโโโโโ
โ ID Token โ
โ Access Token โ
โ Refresh Token โ
โโโโโโโโโ
์ธ๊ฐ์ฝ๋(Authorization code)๋ ์ค๊ฐ๊ตํ์๋จ์ผ๋ก, ์ค์ ๋ฆฌ์์ค ์ ๊ทผ๊ถํ์ ID Token์ด ๊ฐ์ง๊ณ ์๊ณ , OIDC ์ฌ์ฉ์ ์ธ์ฆ(Authentication) ๊ณผ์ ์ Authorization Code๋ฅผ ํตํด ID Token์ ๋ฐ๊ธ๋ฐ์์ผ๋ก์จ ์์ฑ๋๋ค. |
์ค์ต #3) ID Token ๋ฐ๊ธ๊ณผ์
์ด์ ์ค์ต#2์์ ๋ฐ๊ธ๋ฐ์ Authorization Code๋ฅผ ๊ฐ์ง๊ณ ID Token์ ๋ฐ๊ธ๋ฐ์๋ณด์.
์ค์ตํด๋ณด๊ธฐ
ํ ์คํธ ํ์ด์ง (http://localhost:8000)์์ 3 - Token๋ฅผ ํด๋ฆญํ๋ค.
์ค์ต #2์์ ๋ฐ๊ธ๋ฐ์ ์ธ๊ฐ(Authorization)์ฝ๋๋ฅผ ๊ฐ์ง๊ณ ID Token & Refresh Token, Access Token ๋ฑ์ ๋ฐ๊ธ๋ฐ์๋ค.
Token Response ํ๋ ์์๊ฐ๊ธฐ
๊ตฌ๋ถ | ์ค๋ช |
access_token | - ๋ณดํธ๋ ๋ฆฌ์์ค์ ์ ๊ทผํ๊ธฐ ์ํ ํ ํฐ - JWT ํ์์ผ๋ก ์ธ์ฝ๋ฉ๋ ๋ฌธ์์ด - ๋ฆฌ์์ค ์๋ฒ์ ์ ๊ทผํ ๋ ์ฌ์ฉ |
expires_in | - ์ก์ธ์ค ํ ํฐ์ ์ ํจ ์๊ฐ (์ด) |
refresh_expires_in | - ๋ฆฌํ๋ ์ ํ ํฐ์ ์ ํจ ์๊ฐ (์ด) |
refresh_token | - ์ก์ธ์ค ํ ํฐ์ด ๋ง๋ฃ๋์์ ๋ ์๋ก์ด ํ ํฐ์ ๋ฐ๊ธ๋ฐ๊ธฐ ์ํ ํ ํฐ - ์ฌ์ฉ์๊ฐ ๋ค์ ๋ก๊ทธ์ธํ์ง ์์๋ ๋จ |
token_type | - ํ ํฐ์ ํ์
์ ๋ํ๋ - Bearer๋ ํ ํฐ ์์ง์์๊ฒ ๊ถํ์ ๋ถ์ฌ |
id_token | - ์ฌ์ฉ์์ ์ ์ ์ ๋ณด๋ฅผ ํฌํจํ JWT - OIDC์์ ์ถ๊ฐ๋ ํ ํฐ - ์ฌ์ฉ์ ์ธ์ฆ ์ ๋ณด ํฌํจ |
not-before-policy | - ํ ํฐ์ด ์ ํจํด์ง๋ ์์ ์๊ฐ - 0์ ์ฆ์ ์ ํจํจ์ ์๋ฏธ |
session_state | - ํ์ฌ ์ธ์ ์ ๊ณ ์ ์๋ณ์ |
scope | - ํ ํฐ์ด ๊ฐ์ง ๊ถํ ๋ฒ์ - "openid profile email": ๊ธฐ๋ณธ ์ธ์ฆ, ํ๋กํ ์ ๋ณด, ์ด๋ฉ์ผ ์ ๋ณด ์ ๊ทผ ๊ฐ๋ฅ |
id_token, access_token, refresh_token ์ดํดํ๊ธฐ
์ ์ผ ์ค์ํ๊ฑด ์๋ ์ธ ๊ฐ์ง ํ ํฐ์ด๋ค.
์ด ์ธ ํ ํฐ ๋ชจ๋ JWTํ์์ด๋ค.
[ํด๋ผ์ด์ธํธ] [์ธ์ฆ ์๋ฒ] [๋ฆฌ์์ค ์๋ฒ]
โ โ โ
โ โโโโโโโโโโโโ โ โ
โโ>โAccess โโโโโโโโโโโโโโโโโโโโโโโโโ>โ API ์ ๊ทผ
โ โToken โ โ โ
โ โโโโโโโโโโโโ โ โ
โ โ โ
โ โโโโโโโโโโโโ โ โ
โโ>โRefresh โโโโ>โ ์ ํ ํฐ ๋ฐ๊ธ โ
โ โToken โ โ โ
โ โโโโโโโโโโโโ โ โ
โ โ โ
โ โโโโโโโโโโโโ โ โ
โโ>โID Token โโโโ>โ ์ฌ์ฉ์ ์ธ์ฆ โ
โโโโโโโโโโโโ โ โ
- access_token: API ์ ๊ทผ์ฉ ํ ํฐ (API ํธ์ถ ์ ๊ถํ ์ฆ๋ช
)
- ๊ถํ๋ฒ์(Scope) / ๋ฆฌ์์ค ์ ๊ทผ ๊ถํ / ๋ง๋ฃ์๊ฐ / Client ID - refresh_token: ๋ง๋ฃ๋ Access Token ๊ฐฑ์ ์ฉ ํ ํฐ
- ํ ํฐ ๊ฐฑ์ ์ฉ์ผ๋ก ์ต์ํ์ ์ ๋ณด๋ง ๋ด์(๋ณด์์ ๋ณด) - id_token: ์ฌ์ฉ์ ์ธ์ฆ ์ ๋ณด์ฉ ํ ํฐ (์ฌ์ฉ์ ์ ์ ์ ๋ณด ํ์ธ)
- ์ฌ์ฉ์์ ๋ณด / ์ธ์ฆ์์ / ์ธ์ฆ๋ฐฉ๋ฒ / ํ ํฐ๋ฐ๊ธ์
Access Token์ด ๋ง๋ฃ๋๋ฉด ๊ฐ์ง๊ณ ์๋ Refresh Token์ผ๋ก ์ธ์ฆ์๋ฒ์ ์์ฒญํ๊ฒ ๋๋ฉฐ,
์ด๋ Access Token ๋ฟ๋ง์๋๋ผ ๋ชจ๋ Token์ด ๊ฐฑ์ ๋๋ค.
[ํด๋ผ์ด์ธํธ] [์ธ์ฆ ์๋ฒ]
โ โ
โ Refresh Token โ
โโโโโโโโโโโโโโโโโโ> โ
โ โ
โ โ
โ ์๋ก์ด ํ ํฐ ์ธํธ โ
โ <โโโโโโโโโโโโโโโโโโ
โ - Access Token โ
โ - ID Token โ
โ - Refresh Token โ
์ค์ต #4) Token Refresh
์ด์ ์ค์ต#3์์ ๋ฐ๊ธ๋ฐ์ refresh token ๋ฅผ ๊ฐ์ง๊ณ ํ ํฐ์ ๋ชจ๋ ์ฌ๋ฐ๊ธ ํด๋ณด์!
์ค์ตํด๋ณด๊ธฐ
ํ ์คํธ ํ์ด์ง (http://localhost:8000)์์ 4 - Refresh๋ฅผ ํด๋ฆญํ๋ค.
Refresh Request ํ๋์๋ RefreshToken์ด ํฌํจ๋๋ฉฐ,
๋ชจ๋ Token์ ์ฌ์ฌ์ฉ๋์ง ์๊ณ , Refresh์์ฒญ์ด ์ค๋ฉด ๋ชจ๋ ์ฌ๋ฐ๊ธ ๋๋ค.
์ค์ต #5) UserInfo ์์ฒญํ๊ธฐ
Access Token์ผ๋ก UserInfo๋ฅผ ์์ฒญํด๋ณด์.
์ค์ตํด๋ณด๊ธฐ
ํ ์คํธ ํ์ด์ง (http://localhost:8000)์์ 5 - UserInfo๋ฅผ ํด๋ฆญํ๋ค.
UserInfo Endpoint ์ค๋ช
UserInfo Endpoint๋ OIDC์ ์ค์ํ ๊ธฐ๋ฅ ์ค ํ๋์ด๋ฉฐ ์ฃผ์ ํน์ง์ ์๋์ ๊ฐ๋ค.
- ID Token์ ์๋ ์ ๋ณด๋ฅผ ๋ณด์
- ํญ์ ์ต์ ์ฌ์ฉ์ ์ ๋ณด ์ ๊ณต
- scope ์ค์ ์ ๋ฐ๋ผ ๋ฐํ๋๋ ์ ๋ณด๊ฐ ๋ฌ๋ผ์ง
- Access Token์ ๊ถํ ๋ฒ์ ํ์ธ
UserInfo๋ AccessToken์ ์ฌ์ฉํด์ ์์ฒญํ๋ฉฐ ์๋์ ๊ฐ์ ๋ฐฉ์์ผ๋ก ๋์ํ๋ค.
#1. UserInfo Request
โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ
โ ํด๋ผ์ด์ธํธ โ โ UserInfo โ
โ โโโโ GET โโโโโโโ>โ Endpoint โ
โ โ โ โ
โ โ Authorization: โ โ
โ โ Bearer [Access โ โ
โ โ Token] โ โ
โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ
#2. UserInfo Response
โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ
โ ํด๋ผ์ด์ธํธ โ โ UserInfo โ
โ โ<โโ JSON โโโโโโโโ Endpoint โ
โ โ โ โ
โ { โ โ
โ "sub": "...", โ โ
โ "name": "user234 test", โ โ
โ "email": "user01@..." โ โ
โ } โ โ
โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ