keycloakを利用する最低限のメモ
前提・環境
- Mac利用します
- OpenJDK (ver 11.x)インストール済み
- 私のKeycloakの利用目標はREST APIへの認証追加です(なので内容がそっち寄りです)
インストールと起動
インストール
KeycloakはJavaアプリケーションなのでJavaが入っていれば動きます。
こちらからzipをダウンロードして、適当な場所に解答して実行するだけです。
私はhomeディレクトリで解凍しましたが、どこでもいいです。バージョンは12.0.4でした。
起動
cd keycloak-12.0.4/
bash bin/standalone.sh
localhost以外からのアクセスを許可するには standalone.sh -b 0.0.0.0 とします。
動作確認
初期セットアップ
アクセスすると下記のような画面が表示されるので管理者のアカウントを作成しておきます。
ローカルでのテストなので 一旦、ID,PWをadmin,adminにしておきます(真似しちゃダメですよ)。
Adminstration Consoleをクリックします。
管理画面のTOPページにリダイレクトします。ここでいろいろやっていきます。
KeycloakではRealmという概念があり、これが最も上位のグルーピングの管理単位となります。
APIを叩いてみる
基本設定情報の取得
いろいろ設定やendpointを見る(出力割愛)。
curl -s \
http://localhost:8080/auth/realms/master/.well-known/openid-configuration | python -m json.tool
Token取得用のEndpointを抽出。
curl -s \
http://localhost:8080/auth/realms/master/.well-known/openid-configuration | jq -r ".token_endpoint"
http://localhost:8080/auth/realms/master/protocol/openid-connect/token
jq コマンドが使えない場合はbrew install jqで。
リクエストで利用するclient名とsecretを取得する
クライアント
secret
tokenの取得
初期状態で存在している"account"アカウントを利用してみます。
curl -s \
-d "client_id=account" \
-d "client_secret=19beb1ef-d25b-45e7-bb66-6790562e0f04" \
-d "username=admin" \
-d "password=admin" \
-d "grant_type=password" \
-d "scope=openid" \
"http://localhost:8080/auth/realms/master/protocol/openid-connect/token" | python -m json.tool
上記コマンドでtokenが取得できるのはClientの設定が[Direct Access Grants Enabled]になってるから。scope=openidとすることでid_tokenも戻る。
いろいろ戻ってきます。
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJYMGk0Mk1CU2dFb1FGeGpZZEhDOWNzTmlxcS1WdFIwdW53bEVoampCdFpNIn0.eyJleHAiOjE2MTU2OTA2MDksImlhdCI6MTYxNTY5MDU0OSwianRpIjoiMmI3ZGEwMTAtNzkxYy00MzI1LWE4ZjgtOTI0ZDdmODNhODhmIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL2F1dGgvcmVhbG1zL21hc3RlciIsInN1YiI6IjA0OTI1NjIwLTBlOWYtNDRkMC1iNDRhLTA4MGUxZmIwZWRmMCIsInR5cCI6IkJlYXJlciIsImF6cCI6ImFjY291bnQiLCJzZXNzaW9uX3N0YXRlIjoiNGJlZjQzNDQtNmQ4MC00MDA0LWFiYmYtYWNhZjNhYWU5NGE2IiwiYWNyIjoiMSIsInJlc291cmNlX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6Im9wZW5pZCBwcm9maWxlIGVtYWlsIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJhZG1pbiJ9.r96bNksy85Kh-E9G0c4WOHpEuoy7f7KUFDrhV3iORCXz5wPaGKktLxkLfYpnd1xrijRs-amWvic2ZvzCii_pOTozv8kRm1QmGL54h4lOY2Q8PZCAgbDcyajmOoDedweOnGqTzOSGaBJftoMsd0bcoSqxiPtF5N6bcd1_aw-BRaP6HDiGutiKe9KAHI8g_1w-gq4UmVkh-OSa-B8FVXUw6S-gsyMxO6UAa0A_W13H4rXCc9LzpMMtTh3WR1VMoQ3VX8GpzVl9jA9uAI67yzI0RhUeGgBNaHXXgOPVUOj0abNsAXfHh0kVbIaAKWqCML7e2fafCnqVOL7OGUa931JR4g",
"expires_in": 60,
"id_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJYMGk0Mk1CU2dFb1FGeGpZZEhDOWNzTmlxcS1WdFIwdW53bEVoampCdFpNIn0.eyJleHAiOjE2MTU2OTA2MDksImlhdCI6MTYxNTY5MDU0OSwiYXV0aF90aW1lIjowLCJqdGkiOiJhMjU1NGU1OS0wMjgyLTQ1MTItOTdmNC1lN2QyZjQ5YmVmMGEiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODAvYXV0aC9yZWFsbXMvbWFzdGVyIiwiYXVkIjoiYWNjb3VudCIsInN1YiI6IjA0OTI1NjIwLTBlOWYtNDRkMC1iNDRhLTA4MGUxZmIwZWRmMCIsInR5cCI6IklEIiwiYXpwIjoiYWNjb3VudCIsInNlc3Npb25fc3RhdGUiOiI0YmVmNDM0NC02ZDgwLTQwMDQtYWJiZi1hY2FmM2FhZTk0YTYiLCJhdF9oYXNoIjoiRHVyeEpYS3UzX2ltNHRUY2FKbTE3QSIsImFjciI6IjEiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsInByZWZlcnJlZF91c2VybmFtZSI6ImFkbWluIn0.DvohU3Cw8yDLGFHf20PyBV6rxkXilfoe76SMdNm-HxVqamQyJdBPFGPYGk4dUqJVjcVCjit6dgd_Q_hL3y5nGac44UIfZsFaGJ7VFJ_r9YbjcaT3ppDwLj3_yBxmxBsThwsHo1n6WpQVPXALhpleVTa6yMgS13IovOG6QL-dILnweNBNg4LYWd8tAkgbB96S40G0jwlWNwL3Kt4tR2mjZMipjznjhC23W2FgubeNjxwTI8WSvYwGOawlpBemeXu-ma-Y_cLu-VHU7UL8mb1U0GdQbYXt04CNWpo7nSF-H2JuYAnuu_9ivkJ32tlVFitHyLKjFwBOuptizPdtuUUeOQ",
"not-before-policy": 0,
"refresh_expires_in": 1800,
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICI0N2Y5NmFjMS02ZTBhLTQ5NGItYjdlYS02OTk1NDE0MGIwNzgifQ.eyJleHAiOjE2MTU2OTIzNDksImlhdCI6MTYxNTY5MDU0OSwianRpIjoiOTYzMzFhNGYtMWY5OC00YzUzLWFjOTgtYzcxNDk1YzU0ZGM3IiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL2F1dGgvcmVhbG1zL21hc3RlciIsImF1ZCI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MC9hdXRoL3JlYWxtcy9tYXN0ZXIiLCJzdWIiOiIwNDkyNTYyMC0wZTlmLTQ0ZDAtYjQ0YS0wODBlMWZiMGVkZjAiLCJ0eXAiOiJSZWZyZXNoIiwiYXpwIjoiYWNjb3VudCIsInNlc3Npb25fc3RhdGUiOiI0YmVmNDM0NC02ZDgwLTQwMDQtYWJiZi1hY2FmM2FhZTk0YTYiLCJzY29wZSI6Im9wZW5pZCBwcm9maWxlIGVtYWlsIn0.5oOznYptdgOwjK24vYZptDEyu_O4HYLYFp4Vlt7frcA",
"scope": "openid profile email",
"session_state": "4bef4344-6d80-4004-abbf-acaf3aae94a6",
"token_type": "Bearer"
}
tokenの検証
JWTは単独でも検証できるが、検証用のEndpointもります。
curl -s -X POST \
-d "client_id=account" \
-d "client_secret=19beb1ef-d25b-45e7-bb66-6790562e0f04" \
-d "token=eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJYMGk0Mk1CU2dFb1FGeGpZZEhDOWNzTmlxcS1WdFIwdW53bEVoampCdFpNIn0.eyJleHAiOjE2MTU2OTA2MDksImlhdCI6MTYxNTY5MDU0OSwianRpIjoiMmI3ZGEwMTAtNzkxYy00MzI1LWE4ZjgtOTI0ZDdmODNhODhmIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL2F1dGgvcmVhbG1zL21hc3RlciIsInN1YiI6IjA0OTI1NjIwLTBlOWYtNDRkMC1iNDRhLTA4MGUxZmIwZWRmMCIsInR5cCI6IkJlYXJlciIsImF6cCI6ImFjY291bnQiLCJzZXNzaW9uX3N0YXRlIjoiNGJlZjQzNDQtNmQ4MC00MDA0LWFiYmYtYWNhZjNhYWU5NGE2IiwiYWNyIjoiMSIsInJlc291cmNlX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6Im9wZW5pZCBwcm9maWxlIGVtYWlsIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJhZG1pbiJ9.r96bNksy85Kh-E9G0c4WOHpEuoy7f7KUFDrhV3iORCXz5wPaGKktLxkLfYpnd1xrijRs-amWvic2ZvzCii_pOTozv8kRm1QmGL54h4lOY2Q8PZCAgbDcyajmOoDedweOnGqTzOSGaBJftoMsd0bcoSqxiPtF5N6bcd1_aw-BRaP6HDiGutiKe9KAHI8g_1w-gq4UmVkh-OSa-B8FVXUw6S-gsyMxO6UAa0A_W13H4rXCc9LzpMMtTh3WR1VMoQ3VX8GpzVl9jA9uAI67yzI0RhUeGgBNaHXXgOPVUOj0abNsAXfHh0kVbIaAKWqCML7e2fafCnqVOL7OGUa931JR4g" \
"http://localhost:8080/auth/realms/master/protocol/openid-connect/token/introspect" | python -m json.tool
有効のとき
{
"acr": "1",
"active": true,
"azp": "account",
"client_id": "account",
"email_verified": false,
"exp": 1615691183,
"iat": 1615691123,
"iss": "http://localhost:8080/auth/realms/master",
"jti": "197e3010-445a-4bdd-b506-4122121964a3",
"preferred_username": "admin",
"resource_access": {
"account": {
"roles": [
"manage-account",
"manage-account-links",
"view-profile"
]
}
},
"scope": "openid profile email",
"session_state": "b3bf3cd2-bcb8-436c-b681-28b3cfa9427e",
"sub": "04925620-0e9f-44d0-b44a-080e1fb0edf0",
"typ": "Bearer",
"username": "admin"
}
無効のとき
{
"active": false
}
activeがtrueかfalseで判断できる。
Userinfo
userinfoの取得。
時間切れでaccess tokenが上記とは変わってます。
curl -s -X GET \
-H "Content-Type: application/x-www-form-urlencoded" \
-H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJYMGk0Mk1CU2dFb1FGeGpZZEhDOWNzTmlxcS1WdFIwdW53bEVoampCdFpNIn0.eyJleHAiOjE2MTU3NDY1MDIsImlhdCI6MTYxNTc0NjQ0MiwianRpIjoiMmIyNWE0ZjctN2NhZS00MThlLWE0ZDItOTY0OTBlODUxMWJmIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL2F1dGgvcmVhbG1zL21hc3RlciIsInN1YiI6IjA0OTI1NjIwLTBlOWYtNDRkMC1iNDRhLTA4MGUxZmIwZWRmMCIsInR5cCI6IkJlYXJlciIsImF6cCI6ImFjY291bnQiLCJzZXNzaW9uX3N0YXRlIjoiZDJhMjQ0NTItMTU4Ni00M2IzLTlkM2QtZTVkMDUwYzI5NzBmIiwiYWNyIjoiMSIsInJlc291cmNlX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6Im9wZW5pZCBwcm9maWxlIGVtYWlsIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJhZG1pbiJ9.k0tGO2eJf7fJJaPtq6AYGdYy0h1aAVwkKhwC7m08_JUXWv_ZZqH0XNflgt1aYJLKFXB-oxoPJhjLYObyoH84f10DDhI2AKKB2JBtm_qjyDATsOs4haOoaEYi9dS8X-Le4C1jZ23OVCWdxH_xdl_bKdjVVPMe2w7zfqNiXo44ZxkKDY5uHqO1g4GBW7RvRCy6vCcCm622ijO-YfaMrtTqc4e3QkrI7l-PX1hDeqNFGid5zId6YwVnnY62WUznj26uOd3j9Zc7f4i-gXoBkoN3nGbVIzu1Ycg8ebYOkkMTu7ENI1ZetCzL9Q-XuzHo_j-SCeAs_anni8CU9RJjmWZsiA" \
"http://localhost:8080/auth/realms/master/protocol/openid-connect/userinfo" | python -m json.tool
とりあえず下記のような内容が帰ってくる。カスタマイズとかどうやるんだろう。調べます。
{
"email_verified": false,
"preferred_username": "admin",
"sub": "04925620-0e9f-44d0-b44a-080e1fb0edf0"
}