この記事はラクスアドベントカレンダーの15日目の記事です。昨年から1年ぶりの投稿です。
今年は業務で、OpenID ConnectやOAuthやSAMLなど認証・認可プロトコルに触れることが多かったです。
OpenID Connectの勉強をする際に、Relaying Partyを用意するのが面倒なのと、実際のフローを確認したかったので、curlとKeycloak利用してOpenID Connectで認証してみました。
OpenID Connectの仕様書は理解したけど、実際の認証フローの想像がつかない方はぜひ参考にしてみてください。
環境
Keycloakは19.0.2
を利用し、ローカルのDockerでlocalhost:8080
で動作しています。
curlとKeycloakでAuthorization Code Flow
Keycloakの準備
Keycloakには、oidc-sample
というRealmに、rp1
というOpenID ConnectのClientと、admin
というUserを作成しています。
Clientの主に変更・取得した設定は以下になります。
設定 | 値 |
---|---|
Client ID | rp1 |
Valid redirect URIs | http://localhost:3000/oidc |
Client authentication | On |
Client secret |
Credentials タブから取得 |
KeycloakのOpenID Connectプロバイダー情報はhttp://localhost:8080/realms/oidc-sample/.well-known/openid-configurationから取得できます。
今回は以下のエンドポイントを利用します。
エンドポイント名 | エンドポイント |
---|---|
Authorization Endpoint | http://localhost:8080/realms/oidc-sample/protocol/openid-connect/auth |
Token Endpoint | http://localhost:8080/realms/oidc-sample/protocol/openid-connect/token |
UserInfo Endpoint | http://localhost:8080/realms/oidc-sample/protocol/openid-connect/userinfo |
Authorization Code Flow
詳しくは説明しませんが、以下のようなフローになります。
OpenID Connect Core 1.0 incorporating errata set 1から引用- Authentication Request
RP(今回はcurlを実行するPC)がOP(Keycloak)に認証リクエストを送る - Authentication & Authorization
OPはEnd-Userを認証、認可する - Token Request
OPはID TokenとAccess TokenをRPに発行する - UserInfo Request $ Response
RPはAccess Tokenを添えてUserInfo Endpointにリクエストを送り、OPはEnd-UserのClaimを返す
では早速Authentication Requestから実施します。
Authentication Request
IDトークンとアクセストークンを発行するために必要な認証コードを取得するために、Authentication Requestを発行し、Keycloakにログインします。
ブラウザでログインが必要なため、以下のURLにブラウザでアクセスします。
http://localhost:8080/realms/oidc-sample/protocol/openid-connect/auth?response_type=code&client_id=rp1&redirect_uri=http://localhost:3000/oidc&scope=openid
Keycloakのログイン画面が表示されます。
Authentication & Authorization
Keycloakのログイン画面が表示されるので、Userでログインします。ログインに成功すると、redirect_uri
に設定したURLにリダイレクトされますが、localhost:3000
でWebアプリを動かしていないのでエラー画面が出ます。
が、気にせずURLを取得してください。以下のようなURLを取得できると思います。
http://localhost:3000/oidc?session_state=・・・・&code=<認証コード>
code
パラメータが認証コードになります。ではこの認証コードを利用してIDトークンとアクセストークンを発行します。
Token Request
取得した認証コードを利用してToken Endpointで、IDトークンとアクセストークンを発行します。
curl -d "grant_type=authorization_code&code=<認証コード>&redirect_uri=http://localhost:3000/oidc&client_id=rp1&client_secret=<Client secret>" http://localhost:8080/realms/oidc-sample/protocol/openid-connect/token
Token Requestが成功すれば以下のようなToken Responseが返り、IDトークンとアクセストークンを取得できます。
{
"access_token": <アクセストークン>,
"expires_in": 300,
"refresh_expires_in": 1800,
"refresh_token": <リフレッシュトークン>,
"token_type": "Bearer",
"id_token": <IDトークン>,
"not-before-policy": 0,
"session_state": "8468db1c-feb4-4803-bfeb-213149b560cf",
"scope": "openid email profile"
}
jwt.ioなどで各種トークンを確認してみてください。
UserInfo Request $ Response
取得したアクセストークンを利用して、UserInfo EndpointからKeycloakのUser情報を取得します。
curl -H "Authorization: Bearer <アクセストークン>" http://localhost:8080/realms/oidc-sample/protocol/openid-connect/userinfo
以下のようなUser情報を取得できると思います。
{
"sub": <User ID>,
"email_verified": false,
"preferred_username": "admin",
"given_name": "",
"family_name": ""
}
もしアクセストークンの有効期限が切れている場合は、以下のようにリフレッシュトークンを利用して、アクセストークンを再発行してください。
curl -X POST -d "client_id=rp1&client_secret=<Client Secret>&grant_type=refresh_token&refresh_token=<リフレッシュトークン>&scope=openid profile" http://localhost:8080/realms/oidc-sample/protocol/openid-connect/token
以上、curlとKeycloakでAuthorization Code Flowを実践してみました。
終わりに
実際に手で動かすと、より理解が深まると思います。
OpenID Connectの仕様を理解するための手段の1つとして、ぜひ参考にしてみてください。