はじめに
前回からだいぶ時間が空いてしましましたが、今回はOpenID Connectで認可コードを取得するエンドポイントとそれ以降のフローで必要なRPからOpenAMのRestAPIエンドポイントのアクセス方法をご紹介したいと思います。
OpenID Connectの仕様に準拠しているため基本的には他のOPソフトウェアと同じですが、エラー時のレスポンス内容が規定されていないため異なったり、パラメータの値が実装内容により範囲が異なったりといった違いはあるかと思います。
また、第1回から第4回までの内容を踏まえておくとより理解が進むかと思いますので、下記も参考にしてください。
OAuth2.0/OpenID Connectの利用(1) : ソーシャルログインでOpenAMにユーザ認証してみる(Facebook編)
OAuth2.0/OpenID Connectの利用(2) : ソーシャルログインでOpenAMにユーザ認証してみる(Google編)
OAuth2.0/OpenID Connectの利用(3) : OpenAMでOPを立ててmod_auth_openidcと連携する
OAuth2.0/OpenID Connectの利用(4) : OpenID ConnectのIDトークン(JSON Web Token)を理解する
OpenAMのAuthorizationエンドポイント
Basic Client ProfileでOpenAMのAuthorizationエンドポイントから認可コードを受け取る内容を説明します。
OpenAM上のAuthorizationエンドポイントは/oauth2/authorize
です。
以下のようにOPのAuthorizationエンドポイントにリクエストをします。
これはRPが直接OPにリクエストするのではなくユーザーのブラウザ上でRPがリダイレクトを実行します。
ユーザーはOPの認証画面で認証操作をおこなったあと、OPからRPのリダイレクトURIにリダイレクトします。
このAuthorizationエンドポイントではユーザーのブラウザ操作で発生するリクエストとレスポンスです。
実際にはブラウザ上ですが、コマンドで実行した場合はいかのようになります。
# curl -k --request GET \
"https://sso.test.osstech.co.jp/openam/oauth2/authorize?response_type=code
&scope=openid%20profile&client_id=client1&state=3AzO9CyFP3fQkLKhaSkQNjYfgtA
&redirect_uri=https%3A%2F%2Foidcrp.test.osstech.co.jp%2Fportal%2F
&nonce=vs6og3aOTZQts2E5XpDHrokMQ590xpM9hz8meFN4XI0"
実際のリクエストは以下のようにOPに届きます。
GET /openam/oauth2/authorize?response_type=code&scope=openid%20profile&client_id=client1
&state=3AzO9CyFP3fQkLKhaSkQNjYfgtA
&redirect_uri=https%3A%2F%2Foidcrp.test.osstech.co.jp%2Fportal%2F
&nonce=vs6og3aOTZQts2E5XpDHrokMQ590xpM9hz8meFN4XI0 HTTP/1.1
Host: sso.test.osstech.co.jp
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:130.0) Gecko/20100101 Firefox/130.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/png,image/svg+xml,*/*;q=0.8
Accept-Language: ja,en-US;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate, br, zstd
Connection: keep-alive
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: none
Sec-Fetch-User: ?1
Priority: u=0, i
X-Forwarded-Proto: https
X-Forwarded-Port: 443
X-Forwarded-For: xxx.xxx.xxx.xxx
リクエストパラメータ
リクエストパラメータの説明です。
パラメータ | 要否 | 内容 |
---|---|---|
response_type | 必須 | "code"、"token"、"id_token" のいずれかまたは複数をスペース区切りで指定 |
scope | 必須 | 必要なscopeを指定。"openid","profile"やカスタムスコープなど。スペース区切りで指定。 |
client_id | 必須 | クライアントIDを指定 |
redirect_url | 任意 | クライアントへのリダイレクトURLを指定。無くてもエラーにならないが指定した場合はOP上にあらかじめ登録してあるリダイレクトURLの中から指定する。 |
state | 任意 | CSRF対策のためランダムな値を指定。指定した値はこのリクエストの応答にそのまま含まれるためRP側でチェックする。 |
nonce | 任意 | リプレイアタック防止用に任意の値を指定。OPから取得したIDトークンに含まれるnonceと合致するかチェックする。レスポンスにIDトークンが含まれない場合はレスポンス内のnonceパラメータと合致するかチェックする。 |
code_challenge | 任意 | 認可コード横取り防止用に任意の値を指定。access_tokenエンドポイントのアクセスでRPからcode_verifilerを送信し、OPはcode_challenge,code_challenge_methodから算出した値とcode_verifilerが合致するかチェックする。 |
code_challenge_method | 任意 | "S256" もしくは "plain"を指定。code_challengeを付けた場合は必須。 |
※OpenAMのクライアント設定で「code_verifier パラメーターを要求」を有効にしたときはcode_challenge,code_challenge_methodは必須になる。
リダイレクト内容(正常時)
RPへのリダイレクト内容の説明です。
クエリパラメータ名 | 内容 |
---|---|
code | OPで発行された認可コード |
scope | 対象スコープ |
iss | 認可コードの発行元 |
state | リクエストでRPから送ったstateの値。RPはここで送信した値と戻り値が同じかチェックする。 |
client_id | クライアントID |
実際のリダイレクトは以下のようにRPに届きます。
GET https://oidcrp.test.osstech.co.jp/portal/
?code=f1a61db4-5c6c-4b0e-8a70-6a9f0a6b411f
&scope=openid%20profile
&iss=https%3A%2F%2Fsso.test.osstech.co.jp%3A443%2Fopenam%2Foauth2
&state=eU9w3ikVBqamek36x-Dw1VykQBA
&client_id=client1
HTTP/1.1
Host: oidcrp.test.osstech.co.jp
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:131.0) Gecko/20100101 Firefox/131.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/png,image/svg+xml,*/*;q=0.8
Accept-Language: ja,en-US;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate, br, zstd
Referer: https://sso.test.osstech.co.jp/
Connection: keep-alive
Cookie: mod_auth_openidc_state_eU9w3ikVBqamek36x-Dw1VykQBA=eyJhbGciOiAiZGlyIiwgImVuYyI6ICJBMjU2R0NNIn0..AyBwcPIUuWPLVVab.Gr5hILb42NuDjuvfQBHSUlIuUhiGJsrs-uryZljJKeDC4ySXie4U0h4eI8C6Z3FFhzNeykM-Mjgjgi9eRBVI-zXUg1kaDmXGZ0Ze4BBvpVahzlgxXLXnXByncfTtVg4QW2wa6KkZa2WjeyP0HH-8Ka0clWJcdGhIy0DTfRwHvaNGz_G8IYIt6CKO2Qk1jQePSlM0hiE.h1hJyAyMDzg2ceUm46KZQQ; lbcookie=01; ssocookie=AQIC5wM2LY4Sfcyirv7DIO4-silxwIu8u8blLX-HY7M_PnQ.*AAJTSQACMDMAAlNLABQtNDgzNjM1MzA3NDE1MjU3MjE2MAACUzEAAjAx*
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-site
Sec-Fetch-User: ?1
それに対してエラーがあった場合は以下の内容が返ります。
リダイレクト内容(エラー時)
RPへのリダイレクト内容の説明です。
クエリパラメータ名 | 内容 |
---|---|
error | エラーコード |
error_description | エラーの詳細 |
state | リクエストでRPから送られたstateの値 |
エラー時は以下のようにRPに届きます。
GET https://oidcrp.test.osstech.co.jp/portal/
?error_description=Unknown%2Finvalid%20scope%28s%29%3A%20%5Bsms%5D
&state=wgG28nSYdwj5l3YMRxDpNouf2LY
&error=invalid_scope HTTP/1.1
Host: oidcrp.test.osstech.co.jp
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:131.0) Gecko/20100101 Firefox/131.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/png,image/svg+xml,*/*;q=0.8
Accept-Language: ja,en-US;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate, br, zstd
Connection: keep-alive
Cookie: mod_auth_openidc_state_wgG28nSYdwj5l3YMRxDpNouf2LY=eyJhbGciOiAiZGlyIiwgImVuYyI6ICJBMjU2R0NNIn0..UMOGUt7vrosL9hvZ.IegdzNCuSzEHqJqwSSVodIdjBpEa8KhlKe4OBwSJ2qhVML-iSIU7u0Ka25dbYv9tVpcP8rHjKM1sWUeh9l_X4FmteoFh95tY0unH0gS0KFlYFHlC8t70NCbRhBGkP0AAryVcQo_nw6CaWDvK4bapHbVbPZm3mWk429-8ayUThDP7Bnvv6zqIbZi8Irh_mzVi1jIRl4A.9ClOM_Bm-KSmh1C5Z-5CmQ
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: none
Sec-Fetch-User: ?1
OpenAMのRestAPIエンドポイント
OpenID Connectの各フローで主に利用するエンドポイントを紹介していきますが、
以下のエンドポイントについてリクエスト方法と受け取るレスポンスの例を説明していこうと思います。
・Tokenエンドポイント
・UserInfoエンドポイント
・TokenInfoエンドポイント
・Introspectエンドポイント
・Revokeエンドポイント
それでは各エンドポイントの詳細について見ていきましょう。
Tokenエンドポイント
このエンドポイントではアクセストークン、リフレッシュトークン、IDトークンの取得をします。
認可コードから各トークンを取得することやリフレッシュトークンからアクセストークン、リフレッシュトークンを再取得するといった目的があります。
また、特殊な方法として認可コードなしにPassword Grantという方法でアクセストークン、リフレッシュトークン、IDトークンを取得することも可能です。
OpenAM上のTokenエンドポイントは/oauth2/access_token
です。
認可コードから取得
認可コードからアクセストークン、リフレッシュトークン、IDトークンを取得する方法です。
Curlコマンドを利用してリクエストしてJSONでレスポンスを受け取った例です。
# curl -k --request POST \
--user "client1:password" \
--data "grant_type=authorization_code&code=ca1fc3bd-2e51-4793-868e-d087d699f6b8 \
&redirect_uri=https%3A%2F%2Foidcrp.test.osstech.co.jp%2Fportal%2F" \
"https://sso.test.osstech.co.jp/openam/oauth2/access_token"
{
"access_token":"137947c6-843a-4fd7-adc3-44766f97abca",
"refresh_token":"040e023f-db4c-45bd-8145-e2dbe6907d8c",
"scope":"openid profile",
"id_token":"eyAidHlwIjogIkpXVCIsICJhbGciOiAiSFMyNTYiIH0.eyAiYXRfaGFzaCI6ICJqUS03Sk5oVU5JWmhXSEVVcWg4aTN3IiwgInN1YiI6ICJvc3N0ZWNoMSIsICJhdWRpdFRyYWNraW5nSWQiOiAiNGJkZDc4NDUtMjI0YS00NzY4LTk0YWYtNzRjNDU4YWE2M2I3LTQ5NjciLCAiaXNzIjogImh0dHBzOi8vc3NvLnRlc3Qub3NzdGVjaC5jby5qcDo0NDMvb3BlbmFtL29hdXRoMiIsICJ0b2tlbk5hbWUiOiAiaWRfdG9rZW4iLCAibm9uY2UiOiAiNkRZUVFWT3N5bzFHXzdtbVhPSzV2UmtOQ1g5RExJdi01eVhUMGQyMjctSSIsICJhdWQiOiAiY2xpZW50MSIsICJjX2hhc2giOiAiMmVUZ3pPdjBYSFlMQnpRNmgtVkR6QSIsICJvcmcuZm9yZ2Vyb2NrLm9wZW5pZGNvbm5lY3Qub3BzIjogIjhmYjhmNDFlLTc3YzMtNGNjMi1iMjUwLWJjMzcxYWY3ZGY5MiIsICJhenAiOiAiY2xpZW50MSIsICJhdXRoX3RpbWUiOiAxNzI4NTI4ODk5LCAicmVhbG0iOiAiL3VzciIsICJleHAiOiAxNzI4NTMyNjEwLCAidG9rZW5UeXBlIjogIkpXVFRva2VuIiwgImlhdCI6IDE3Mjg1MjkwMTAgfQ._fqZXLlnpU3E56k75X9zvxyppsiNRhrNmYgdQj0Vp4E",
"token_type":"Bearer",
"expires_in":3599,
"nonce":"6DYQQVOsyo1G_7mmXOK5vRkNCX9DLIv-5yXT0d227-I"
}
実際のリクエストは以下のようにOPに届きます。
POST /openam/oauth2/access_token HTTP/1.1
Host: sso.test.osstech.co.jp
Authorization: Basic Y2xpZW50MTpwYXNzd29yZA==
User-Agent: curl/7.61.1
Accept: */*
Content-Length: 138
Content-Type: application/x-www-form-urlencoded
X-Forwarded-Proto: https
X-Forwarded-Port: 443
X-Forwarded-For: xxx.xxx.xxx.xxx
grant_type=authorization_code
&code=ca1fc3bd-2e51-4793-868e-d087d699f6b8
&redirect_uri=https%3A%2F%2Foidcrp.test.osstech.co.jp%2Fportal%2F
Authorizationヘッダ
Authorizationヘッダの説明です。
Basicの後にクライアントID:クライアントシークレットをBase64エンコードして指定します。
"Authorization: Basic Y2xpZW50MTpwYXNzd29yZA=="
コマンドでは下記のようになります。
# echo -n "client1:password" | base64
Y2xpZW50MTpwYXNzd29yZA==
リクエストパラメータ
リクエストパラメータの説明です。
パラメータ | 要否 | 内容 |
---|---|---|
grant_type | 必須 | "authorization_code" を指定 |
code | 必須 | OPから受け取った認可コードを指定 |
redirect_url | 必須 | クライアントへのリダイレクトURLを指定 |
client_id | 任意 | エンドポイントのクライアント認証方法をclient_secret_postにしている場合はクライアントIDを指定 |
client_secret | 任意 | エンドポイントのクライアント認証方法をclient_secret_postにしている場合はクライアントシークレットを指定 |
code_verifier | 任意 | 認可コードの検証値を指定。 |
レスポンス内容(正常時)
RPへのレスポンス内容の説明です。
HTTPステータス: 200(OK)
クレーム名 | 要否 | 内容 |
---|---|---|
access_token | 必須 | アクセストークン |
refresh_token | 任意 | リフレッシュトークン。クライアントで発行する設定とした場合。 |
scope | 必須 | 適用したスコープ |
id_token | 任意 | IDトークン。scopeに"opneid"が指定されている等。 RPはここでIDトークンに含まれる署名検証でトークンが偽装されていないかチェックする。 そのあとでIDトークンに含まれるnonceがRPで送信した値と同じかチェックする。また、他のクレーム検証もおこなう。 ※詳しくは第4回の「OpenID ConnectのIDトークン(JSON Web Token)を理解する」を参照。 |
token_type | 必須 | トークンタイプ。"Bearer"固定 |
expires_in | 必須 | アクセストークンの有効期限(秒) |
nonce | 任意 | OPに送信したリプレイアタック防止用の値。RPはここで送信した値と戻り値が同じかチェックする。scopeでopenidを指定してIDトークンを受け取った場合はこの値ではなくid_tokenに含まれるnonceでチェックする。 |
RPでは以下のようにレスポンスを受け取ります。
HTTP/1.1 200 OK
Date: Thu, 10 Oct 2024 03:58:08 GMT
Server: Restlet-Framework/2.3.4
Cache-Control: no-store
Accept-Ranges: bytes
Vary: Accept-Charset,Accept-Encoding,Accept-Language,Accept
Pragma: no-cache
Content-Type: application/json
Connection: close
Transfer-Encoding: chunked
3f9
{
"access_token":"1b67f909-4a95-44df-88f1-35ca0f78346e",
"refresh_token":"53e8b7b7-b21d-4824-b8ad-3b99589266fc",
"scope":"openid profile",
"id_token":"eyAidHlwIjogIkpXVCIsICJhbGciOiAiSFMyNTYiIH0.eyAiYXRfaGFzaCI6ICJNYkhjTFRuZzlUTEJvRW9hTjJwd1l3IiwgInN1YiI6ICJvc3N0ZWNoMSIsICJhdWRpdFRyYWNraW5nSWQiOiAiNGJkZDc4NDUtMjI0YS00NzY4LTk0YWYtNzRjNDU4YWE2M2I3LTUzMTQiLCAiaXNzIjogImh0dHBzOi8vc3NvLnRlc3Qub3NzdGVjaC5jby5qcDo0NDMvb3BlbmFtL29hdXRoMiIsICJ0b2tlbk5hbWUiOiAiaWRfdG9rZW4iLCAibm9uY2UiOiAiZlJraWJGNW9uSUR2X1VNLTR1S2w2RGxuSk9lMzg1Zm9CNFlPZFZoTV9hTSIsICJhdWQiOiAiY2xpZW50MSIsICJjX2hhc2giOiAiTExvOWdpZHViYldCeVhxR1hrQWlOdyIsICJvcmcuZm9yZ2Vyb2NrLm9wZW5pZGNvbm5lY3Qub3BzIjogImI3MDljM2YxLWYzYjktNDA2Yi04MTIwLTc2YjVjZjJjNzNkYSIsICJhenAiOiAiY2xpZW50MSIsICJhdXRoX3RpbWUiOiAxNzI4NTMyNDg5LCAicmVhbG0iOiAiL3VzciIsICJleHAiOiAxNzI4NTM2Mjg4LCAidG9rZW5UeXBlIjogIkpXVFRva2VuIiwgImlhdCI6IDE3Mjg1MzI2ODggfQ._O7ajurVZcZ2mFWYCtGCVzzwUWrYYiAV_zfK9g3BzZw",
"token_type":"Bearer",
"expires_in":3599,
"nonce":"fRkibF5onIDv_UM-4uKl6DlnJOe385foB4YOdVhM_aM"
}
それに対してエラーがあった場合は以下の内容が返ります。
レスポンス内容(エラー時)
HTTPステータス: 400(Bad Request) または 401(Unauthorized)
クエリパラメータ名 | 内容 |
---|---|
error | エラーコード |
error_description | エラーの詳細 |
エラー時は以下のようにRPに届きます。
HTTP/1.1 400 Bad Request
Date: Thu, 10 Oct 2024 07:35:52 GMT
Server: Restlet-Framework/2.3.4
Cache-Control: no-store
Accept-Ranges: bytes
Vary: Accept-Charset,Accept-Encoding,Accept-Language,Accept
Pragma: no-cache
Content-Type: application/json
Connection: close
Transfer-Encoding: chunked
6a
{
"error_description":"The provided access grant is invalid, expired, or revoked.",
"error":"invalid_grant"
}
リフレッシュトークンから取得
リフレッシュトークンからアクセストークン、リフレッシュトークンを再取得する方法です。
Curlコマンドを利用してリクエストしてJSONでレスポンスを受け取った例です。
# curl -k --request POST \
--user "client1:password" \
--data "grant_type=refresh_token&refresh_token=aeecaf3a-cd8f-4158-b56f-f7888ca83cf3" \
"https://sso.test.osstech.co.jp/openam/oauth2/access_token"
{
"access_token":"1a50bdb6-0daf-4202-8bda-50e79c67f1f8",
"refresh_token":"fcb165df-6fdb-476a-8606-a979433bdbb0",
"scope":"openid profile",
"id_token":"eyAidHlwIjogIkpXVCIsICJhbGciOiAiSFMyNTYiIH0.eyAiYXRfaGFzaCI6ICJOYmhtOVB3blYyRWRpMXdBSkJhN2xRIiwgInN1YiI6ICJvc3N0ZWNoMSIsICJhdWRpdFRyYWNraW5nSWQiOiAiNGJkZDc4NDUtMjI0YS00NzY4LTk0YWYtNzRjNDU4YWE2M2I3LTU0MTciLCAiaXNzIjogImh0dHBzOi8vc3NvLnRlc3Qub3NzdGVjaC5jby5qcDo0NDMvb3BlbmFtL29hdXRoMiIsICJ0b2tlbk5hbWUiOiAiaWRfdG9rZW4iLCAiYXVkIjogImNsaWVudDEiLCAib3JnLmZvcmdlcm9jay5vcGVuaWRjb25uZWN0Lm9wcyI6ICIxMzk5ZWExMy0zNGIxLTQ0NTgtODEzZC02OTlhYjE3ZDgyYzciLCAiYXpwIjogImNsaWVudDEiLCAiYXV0aF90aW1lIjogMTcyODUzNjQzOSwgInJlYWxtIjogIi91c3IiLCAiZXhwIjogMTcyODU0MDAzOSwgInRva2VuVHlwZSI6ICJKV1RUb2tlbiIsICJpYXQiOiAxNzI4NTM2NDM5IH0.OGTMf9NZ-uSYhpwXzs_v1qtiGf-yHshL7BO7eRB0sQw",
"token_type":"Bearer",
"expires_in":3599
}
実際のリクエストは以下のようにOPに届きます。
POST /openam/oauth2/access_token HTTP/1.1
Host: sso.test.osstech.co.jp
Authorization: Basic Y2xpZW50MTpwYXNzd29yZA==
User-Agent: curl/7.61.1
Accept: */*
Content-Length: 75
Content-Type: application/x-www-form-urlencoded
grant_type=refresh_token&refresh_token=aeecaf3a-cd8f-4158-b56f-f7888ca83cf3
Authorizationヘッダ
Authorizationヘッダの説明です。
Basicの後にクライアントID:クライアントシークレットをBase64エンコードして指定します。
"Authorization: Basic Y2xpZW50MTpwYXNzd29yZA=="
リクエストパラメータ
リクエストパラメータの説明です。
パラメータ | 要否 | 内容 |
---|---|---|
grant_type | 必須 | "refresh_token" を指定 |
refresh_token | 必須 | OPから受け取ったリフレッシュトークンを指定 |
レスポンス内容(正常時)
RPへのレスポンス内容の説明です。
HTTPステータス: 200(OK)
クレーム名 | 要否 | 内容 |
---|---|---|
access_token | 必須 | アクセストークン |
refresh_token | 必須 | リフレッシュトークン。このときクライアントで発行する設定となっている。 |
scope | 必須 | 適用したスコープ |
id_token | 任意 | IDトークン。scopeに"opneid"が指定されている等。 |
token_type | 必須 | トークンタイプ。"Bearer"固定 |
expires_in | 必須 | アクセストークンの有効期限(秒) |
RPでは以下のようにレスポンスを受け取ります。
HTTP/1.1 200 OK
Date: Thu, 10 Oct 2024 05:00:39 GMT
Server: Restlet-Framework/2.3.4
Cache-Control: no-store
Accept-Ranges: bytes
Vary: Accept-Charset,Accept-Encoding,Accept-Language,Accept
Pragma: no-cache
Content-Type: application/json
Connection: close
Transfer-Encoding: chunked
348
{
"access_token":"1a50bdb6-0daf-4202-8bda-50e79c67f1f8",
"refresh_token":"fcb165df-6fdb-476a-8606-a979433bdbb0",
"scope":"openid profile",
"id_token":"eyAidHlwIjogIkpXVCIsICJhbGciOiAiSFMyNTYiIH0.eyAiYXRfaGFzaCI6ICJOYmhtOVB3blYyRWRpMXdBSkJhN2xRIiwgInN1YiI6ICJvc3N0ZWNoMSIsICJhdWRpdFRyYWNraW5nSWQiOiAiNGJkZDc4NDUtMjI0YS00NzY4LTk0YWYtNzRjNDU4YWE2M2I3LTU0MTciLCAiaXNzIjogImh0dHBzOi8vc3NvLnRlc3Qub3NzdGVjaC5jby5qcDo0NDMvb3BlbmFtL29hdXRoMiIsICJ0b2tlbk5hbWUiOiAiaWRfdG9rZW4iLCAiYXVkIjogImNsaWVudDEiLCAib3JnLmZvcmdlcm9jay5vcGVuaWRjb25uZWN0Lm9wcyI6ICIxMzk5ZWExMy0zNGIxLTQ0NTgtODEzZC02OTlhYjE3ZDgyYzciLCAiYXpwIjogImNsaWVudDEiLCAiYXV0aF90aW1lIjogMTcyODUzNjQzOSwgInJlYWxtIjogIi91c3IiLCAiZXhwIjogMTcyODU0MDAzOSwgInRva2VuVHlwZSI6ICJKV1RUb2tlbiIsICJpYXQiOiAxNzI4NTM2NDM5IH0.OGTMf9NZ-uSYhpwXzs_v1qtiGf-yHshL7BO7eRB0sQw",
"token_type":"Bearer",
"expires_in":3599
}
それに対してエラーがあった場合は以下の内容が返ります。
レスポンス内容(エラー時)
RPへのレスポンス内容の説明です。
HTTPステータス: 400(Bad Request) または 401(Unauthorized)
クエリパラメータ名 | 内容 |
---|---|
error | エラーコード |
error_description | エラーの詳細 |
エラー時は以下のようにRPに届きます。
HTTP/1.1 400 Bad Request
Date: Thu, 10 Oct 2024 07:44:20 GMT
Server: Restlet-Framework/2.3.4
Cache-Control: no-store
Accept-Ranges: bytes
Vary: Accept-Charset,Accept-Encoding,Accept-Language,Accept
Pragma: no-cache
Content-Type: application/json
Connection: close
Transfer-Encoding: chunked
40
{
"error_description":"grant is invalid",
"error":"invalid_grant"
}
認可コードなしで取得
認可コードなしにPassword Grantという方法でアクセストークン、リフレッシュトークン、IDトークンを取得する方法です。
※OpenAMではサービスのOAuth2プロバイダとエージェントのOAuth2.0クライアントの設定で、グラントタイプにpasswordを追加しておきます。
また、ユーザー認証が必要なので認証フローはシンプルなID/パスワード認証のみでおこなえる必要があります。
Curlコマンドを利用してリクエストしてJSONでレスポンスを受け取った例です。
# curl -k --request POST \
--user "client1:password" \
--data "realm=usr&auth_chain=ldapService&grant_type=password&username=osstech1&password=password&scope=openid%20profile" \
"https://sso.test.osstech.co.jp/openam/oauth2/access_token"
{
"access_token":"e80c9f1a-f694-4bed-9931-b5490c82f095",
"refresh_token":"41cef83e-5db3-4f36-aa62-61424851783a",
"scope":"openid profile",
"id_token":"eyAidHlwIjogIkpXVCIsICJhbGciOiAiSFMyNTYiIH0.eyAiYXRfaGFzaCI6ICJ3WG85NHk1UklQVlFZci1DZVU5aExBIiwgInN1YiI6ICJvc3N0ZWNoMSIsICJhdWRpdFRyYWNraW5nSWQiOiAiNGJkZDc4NDUtMjI0YS00NzY4LTk0YWYtNzRjNDU4YWE2M2I3LTU3ODMiLCAiaXNzIjogImh0dHBzOi8vc3NvLnRlc3Qub3NzdGVjaC5jby5qcDo0NDMvb3BlbmFtL29hdXRoMiIsICJ0b2tlbk5hbWUiOiAiaWRfdG9rZW4iLCAiYXVkIjogImNsaWVudDEiLCAib3JnLmZvcmdlcm9jay5vcGVuaWRjb25uZWN0Lm9wcyI6ICI3ODIxNDllOC02MGM2LTQyYTYtOWJlNC02NmM4ZTEyOGZjNzYiLCAiYXpwIjogImNsaWVudDEiLCAiYXV0aF90aW1lIjogMTcyODU0NzA1OSwgInJlYWxtIjogIi91c3IiLCAiZXhwIjogMTcyODU1MDY1OSwgInRva2VuVHlwZSI6ICJKV1RUb2tlbiIsICJpYXQiOiAxNzI4NTQ3MDU5IH0.9pd9cc8ICMRr7l9xPjp2X0DlGN8zxCt1fQXWfAzNtXc",
"token_type":"Bearer",
"expires_in":3599
}
実際のリクエストは以下のようにOPに届きます。
POST /openam/oauth2/access_token HTTP/1.1
Host: sso.test.osstech.co.jp
Authorization: Basic Y2xpZW50MTpwYXNzd29yZA==
User-Agent: curl/7.61.1
Accept: */*
Content-Length: 111
Content-Type: application/x-www-form-urlencoded
realm=usr&auth_chain=ldapService&grant_type=password&username=osstech1&password=password&scope=openid%20profile
Authorizationヘッダ
Authorizationヘッダの説明です。
Basicの後にクライアントID:クライアントシークレットをBase64エンコードして指定します。
"Authorization: Basic Y2xpZW50MTpwYXNzd29yZA=="
リクエストパラメータ
リクエストパラメータの説明です。
パラメータ | 要否 | 内容 |
---|---|---|
realm | 任意 | OpenAM上の対象レルム |
auth_chain | 必須 | OpenAM上の指定する認証フロー |
grant_type | 必須 | "password" を指定 |
username | 必須 | 認証するユーザーのID |
password | 必須 | 認証するユーザーのパスワード |
scope | 任意 | 対象スコープ |
レスポンス内容(正常時)
RPへのレスポンス内容の説明です。
HTTPステータス: 200(OK)
クレーム名 | 要否 | 内容 |
---|---|---|
access_token | 必須 | アクセストークン |
refresh_token | 任意 | リフレッシュトークン。クライアントで発行する設定とした場合。 |
scope | 必須 | 適用したスコープ |
id_token | 任意 | IDトークン。scopeに"opneid"が指定されている等。 |
token_type | 必須 | トークンタイプ。"Bearer"固定 |
expires_in | 必須 | アクセストークンの有効期限(秒) |
RPでは以下のようにレスポンスを受け取ります。
HTTP/1.1 200 OK
Date: Thu, 10 Oct 2024 07:57:39 GMT
Server: Restlet-Framework/2.3.4
Cache-Control: no-store
Accept-Ranges: bytes
Vary: Accept-Charset,Accept-Encoding,Accept-Language,Accept
Pragma: no-cache
Content-Type: application/json
Connection: close
Transfer-Encoding: chunked
348
{
"access_token":"e80c9f1a-f694-4bed-9931-b5490c82f095",
"refresh_token":"41cef83e-5db3-4f36-aa62-61424851783a",
"scope":"openid profile",
"id_token":"eyAidHlwIjogIkpXVCIsICJhbGciOiAiSFMyNTYiIH0.eyAiYXRfaGFzaCI6ICJ3WG85NHk1UklQVlFZci1DZVU5aExBIiwgInN1YiI6ICJvc3N0ZWNoMSIsICJhdWRpdFRyYWNraW5nSWQiOiAiNGJkZDc4NDUtMjI0YS00NzY4LTk0YWYtNzRjNDU4YWE2M2I3LTU3ODMiLCAiaXNzIjogImh0dHBzOi8vc3NvLnRlc3Qub3NzdGVjaC5jby5qcDo0NDMvb3BlbmFtL29hdXRoMiIsICJ0b2tlbk5hbWUiOiAiaWRfdG9rZW4iLCAiYXVkIjogImNsaWVudDEiLCAib3JnLmZvcmdlcm9jay5vcGVuaWRjb25uZWN0Lm9wcyI6ICI3ODIxNDllOC02MGM2LTQyYTYtOWJlNC02NmM4ZTEyOGZjNzYiLCAiYXpwIjogImNsaWVudDEiLCAiYXV0aF90aW1lIjogMTcyODU0NzA1OSwgInJlYWxtIjogIi91c3IiLCAiZXhwIjogMTcyODU1MDY1OSwgInRva2VuVHlwZSI6ICJKV1RUb2tlbiIsICJpYXQiOiAxNzI4NTQ3MDU5IH0.9pd9cc8ICMRr7l9xPjp2X0DlGN8zxCt1fQXWfAzNtXc",
"token_type":"Bearer",
"expires_in":3599
}
それに対してエラーがあった場合は以下の内容が返ります。
レスポンス内容(エラー時)
RPへのレスポンス内容の説明です。
HTTPステータス: 400(Bad Request) または 401(Unauthorized)
クエリパラメータ名 | 内容 |
---|---|
error | エラーコード |
error_description | エラーの詳細 |
エラー時は以下のようにRPに届きます。
HTTP/1.1 400 Bad Request
Date: Thu, 10 Oct 2024 08:14:05 GMT
Server: Restlet-Framework/2.3.4
Cache-Control: no-store
Accept-Ranges: bytes
Vary: Accept-Charset,Accept-Encoding,Accept-Language,Accept
Pragma: no-cache
Content-Type: application/json
Connection: close
Transfer-Encoding: chunked
4f
{
"error_description":"Unknown/invalid scope(s): [sms]",
"error":"invalid_scope"}
UserInfoエンドポイント
このエンドポイントではアクセストークンからユーザー情報を取得します。
含まれるユーザー情報はアクセストークンを取得するまでに指定されているscopeの範囲になります。
OpenAM上のUserInfoエンドポイントは/oauth2/userinfo
です。
Curlコマンドを利用してリクエストしてJSONでレスポンスを受け取った例です。
# curl -k --request POST \
--header "Authorization: Bearer 9f9db13a-ccd6-4369-b59d-3177efec05b2" \
--data "{}" \
"https://sso.test.osstech.co.jp/openam/oauth2/userinfo"
{
"sub":"osstech1",
"name":"osstech1-cn",
"family_name":"osstech1-sn"
}
実際のリクエストは以下のようにOPに届きます。
POST /openam/oauth2/userinfo HTTP/1.1
Host: sso.test.osstech.co.jp
User-Agent: curl/7.61.1
Accept: */*
Authorization: Bearer 9f9db13a-ccd6-4369-b59d-3177efec05b2
Content-Length: 2
Content-Type: application/x-www-form-urlencoded
{}
Authorizationヘッダ
Authorizationヘッダの説明です。
Bearerの後にアクセストークンを指定します。
"Authorization: Bearer 9f9db13a-ccd6-4369-b59d-3177efec05b2"
リクエストパラメータはありません。
レスポンス内容(正常時)
RPへのレスポンス内容の説明です。
HTTPステータス: 200(OK)
クレーム名 | 要否 | 内容 |
---|---|---|
sub | 必須 | ユーザー識別子 |
xxx | 任意 | scopeで指定された範囲のユーザークレーム。 |
RPでは以下のようにレスポンスを受け取ります。
HTTP/1.1 200 OK
Date: Tue, 15 Oct 2024 04:11:58 GMT
Server: Restlet-Framework/2.3.4
Accept-Ranges: bytes
Vary: Accept-Charset,Accept-Encoding,Accept-Language,Accept
Content-Type: application/json;charset=UTF-8
Connection: close
Transfer-Encoding: chunked
43
{
"sub":"osstech1",
"name":"osstech1-cn",
"family_name":"osstech1-sn"
}
それに対してエラーがあった場合は以下の内容が返ります。
レスポンス内容(エラー時)
RPへのレスポンス内容の説明です。
HTTPステータス: 401(Unauthorized)
クエリパラメータ名 | 内容 |
---|---|
error | エラーコード |
error_description | エラーの詳細 |
エラー時は以下のようにRPに届きます。
HTTP/1.1 401 Unauthorized
Date: Tue, 15 Oct 2024 04:24:59 GMT
Server: Restlet-Framework/2.3.4
Accept-Ranges: bytes
Vary: Accept-Charset,Accept-Encoding,Accept-Language,Accept
Content-Type: application/json
Connection: close
Transfer-Encoding: chunked
87
{
"error_description":"The access token provided is expired, revoked, malformed, or invalid for other reasons.",
"error":"invalid_token"
}
TokenInfoエンドポイント
このエンドポイントではアクセストークンからアクセストークンに関する情報を取得します。
主にアクセストークンに紐づけられたscopeやグラントタイプなどです。
OpenAM上のTokenInfoエンドポイントは/oauth2/tokeninfo
です。
Curlコマンドを利用してリクエストしてJSONでレスポンスを受け取った例です。
# curl -k --request GET \
https://sso.test.osstech.co.jp/openam/oauth2/tokeninfo?access_token=46fa3d20-6e4f-46bd-b695-a159a10fbad2
{
"access_token":"46fa3d20-6e4f-46bd-b695-a159a10fbad2",
"grant_type":"authorization_code",
"openid":"",
"scope":["openid","profile"],
"profile":"",
"realm":"/usr",
"token_type":"Bearer",
"expires_in":3567,
"client_id":"client1"
}
実際のリクエストは以下のようにOPに届きます。
GET /openam/oauth2/tokeninfo?access_token=46fa3d20-6e4f-46bd-b695-a159a10fbad2 HTTP/1.1
Host: sso.test.osstech.co.jp
User-Agent: curl/7.61.1
Accept: */*
Authorizationヘッダはありません。
リクエストパラメータ
リクエストパラメータの説明です。
パラメータ | 要否 | 内容 |
---|---|---|
access_token | 必須 | 検索対象のアクセストークン |
レスポンス内容(正常時)
RPへのレスポンス内容の説明です。
HTTPステータス: 200(OK)
クレーム名 | 要否 | 内容 |
---|---|---|
access_token | 必須 | 検索対象のアクセストークン |
grant_type | 必須 | アクセストークンを取得した際のグラントタイプ |
scope | 必須 | アクセストークンに紐づけられたスコープ。 |
realm | 必須 | OpenAM上の対象レルム。 |
token_type | 必須 | アクセストークンのタイプ。 |
expires_in | 必須 | アクセストークンの有効期限(秒)。 |
client_id | 必須 | クライアントID。 |
RPでは以下のようにレスポンスを受け取ります。
HTTP/1.1 200 OK
Date: Tue, 15 Oct 2024 05:14:00 GMT
Server: Restlet-Framework/2.3.4
Cache-Control: no-cache, no-store
Accept-Ranges: bytes
Vary: Accept-Charset,Accept-Encoding,Accept-Language,Accept
Content-Type: application/json
Connection: close
Transfer-Encoding: chunked
d2
{
"access_token":"46fa3d20-6e4f-46bd-b695-a159a10fbad2",
"grant_type":"authorization_code",
"openid":"",
"scope":["openid","profile"],
"profile":"",
"realm":"/usr",
"token_type":"Bearer",
"expires_in":3567,
"client_id":"client1"
}
それに対してエラーがあった場合は以下の内容が返ります。
レスポンス内容(エラー時)
RPへのレスポンス内容の説明です。
HTTPステータス: 401(Unauthorized)
クエリパラメータ名 | 内容 |
---|---|
error | エラーコード |
error_description | エラーの詳細 |
エラー時は以下のようにRPに届きます。
HTTP/1.1 401 Unauthorized
Date: Tue, 15 Oct 2024 05:29:24 GMT
Server: Restlet-Framework/2.3.4
Accept-Ranges: bytes
Vary: Accept-Charset,Accept-Encoding,Accept-Language,Accept
Content-Type: application/json
Connection: close
Transfer-Encoding: chunked
87
{
"error_description":"The access token provided is expired, revoked, malformed, or invalid for other reasons.",
"error":"invalid_token"
}
Introspectエンドポイント
このエンドポイントではアクセストークンあるいはリフレッシュトークンが有効か無効かを検証します。
OpenAM上のIntrospectエンドポイントは/oauth2/introspect
です。
Curlコマンドを利用してリクエストしてJSONでレスポンスを受け取った例です。
# curl -k --request POST \
--user "client1:password" \
--data "token=7bfd0fc7-f97e-425c-ad16-e87709194179" \
https://sso.test.osstech.co.jp/openam/oauth2/introspect
{
"active":true,
"scope":"openid profile",
"client_id":"client1",
"user_id":"osstech1",
"token_type":"access_token",
"exp":1729060368,
"sub":"osstech1",
"iss":"https://sso.test.osstech.co.jp:443/openam/oauth2"
}
実際のリクエストは以下のようにOPに届きます。
POST /openam/oauth2/introspect HTTP/1.1
Host: sso.test.osstech.co.jp
Authorization: Basic Y2xpZW50MTpwYXNzd29yZA==
User-Agent: curl/7.61.1
Accept: */*
Content-Length: 42
Content-Type: application/x-www-form-urlencoded
token=7bfd0fc7-f97e-425c-ad16-e87709194179
Authorizationヘッダ
Authorizationヘッダの説明です。
Basicの後にクライアントID:クライアントシークレットをBase64エンコードして指定します。
"Authorization: Basic Y2xpZW50MTpwYXNzd29yZA=="
リクエストパラメータ
リクエストパラメータの説明です。
パラメータ | 要否 | 内容 |
---|---|---|
token | 必須 | 検証対象のアクセストークンまたはリフレッシュトークン |
レスポンス内容(正常時)
RPへのレスポンス内容の説明です。
HTTPステータス: 200(OK)
クレーム名 | 要否 | 内容 |
---|---|---|
active | 必須 | true(有効) or false(無効) |
scope | 必須(有効時) | 適用したスコープ。 |
client_id | 必須(有効時) | クライアントID。 |
user_id | 必須(有効時) | 認証されたユーザーID。 |
token_type | 必須(有効時) | "access_token" or "refresh_token" |
exp | 必須(有効時) | トークンの有効期限(タイムスタンプ:秒)。 |
sub | 必須(有効時) | ユーザー識別子 |
iss | 必須(有効時) | トークンの発行元。 |
RPでは以下のようにレスポンスを受け取ります。
【トークンが有効のとき】
HTTP/1.1 200 OK
Date: Wed, 16 Oct 2024 05:34:22 GMT
Server: Restlet-Framework/2.3.4
Accept-Ranges: bytes
Vary: Accept-Charset,Accept-Encoding,Accept-Language,Accept
Content-Type: application/json;charset=UTF-8
Connection: close
Transfer-Encoding: chunked
ca
{
"active":true,
"scope":"openid profile",
"client_id":"client1",
"user_id":"osstech1",
"token_type":"access_token",
"exp":1729060368,
"sub":"osstech1",
"iss":"https://sso.test.osstech.co.jp:443/openam/oauth2"
}
【トークンが無効のとき】
HTTP/1.1 200 OK
Date: Wed, 16 Oct 2024 05:47:55 GMT
Server: Restlet-Framework/2.3.4
Accept-Ranges: bytes
Vary: Accept-Charset,Accept-Encoding,Accept-Language,Accept
Content-Type: application/json;charset=UTF-8
Connection: close
Transfer-Encoding: chunked
10
{"active":false}
それに対してエラーがあった場合は以下の内容が返ります。
レスポンス内容(エラー時)
RPへのレスポンス内容の説明です。
HTTPステータス: 401(Unauthorized)
クエリパラメータ名 | 内容 |
---|---|
error | エラーコード |
error_description | エラーの詳細 |
エラー時は以下のようにRPに届きます。
HTTP/1.1 401 Unauthorized
Date: Wed, 16 Oct 2024 05:52:32 GMT
Server: Restlet-Framework/2.3.4
Accept-Ranges: bytes
Vary: Accept-Charset,Accept-Encoding,Accept-Language,Accept
Content-Type: application/json
Connection: close
Transfer-Encoding: chunked
4d
{
"error_description":"Client authentication failed",
"error":"invalid_client"
}
Revokeエンドポイント
このエンドポイントではアクセストークンあるいはリフレッシュトークンを破棄します。
OpenAM上のRevokeエンドポイントは/oauth2/token/revoke
です。
Curlコマンドを利用してリクエストしてJSONでレスポンスを受け取った例です。
# curl -k --request POST \
--user "client1:password" \
--data "token=186adf8c-d607-49e6-a354-2ab5c3b27012" \
http://sso.test.osstech.co.jp/openam/oauth2/token/revoke
{}
実際のリクエストは以下のようにOPに届きます。
POST /openam/oauth2/token/revoke HTTP/1.1
Host: sso.test.osstech.co.jp
Authorization: Basic Y2xpZW50MTpwYXNzd29yZA==
User-Agent: curl/7.61.1
Accept: */*
Content-Length: 42
Content-Type: application/x-www-form-urlencoded
token=186adf8c-d607-49e6-a354-2ab5c3b27012
Authorizationヘッダ
Authorizationヘッダの説明です。
Basicの後にクライアントID:クライアントシークレットをBase64エンコードして指定します。
"Authorization: Basic Y2xpZW50MTpwYXNzd29yZA=="
リクエストパラメータ
リクエストパラメータの説明です。
パラメータ | 要否 | 内容 |
---|---|---|
token | 必須 | 破棄対象のアクセストークンまたはリフレッシュトークン |
レスポンス内容(正常時)
RPへのレスポンス内容の説明です。
HTTPステータス: 200(OK)
クレームは空となります。
RPでは以下のようにレスポンスを受け取ります。
HTTP/1.1 200 OK
Date: Wed, 16 Oct 2024 07:31:07 GMT
Server: Restlet-Framework/2.3.4
Accept-Ranges: bytes
Vary: Accept-Charset,Accept-Encoding,Accept-Language,Accept
Content-Type: application/json;charset=UTF-8
Connection: close
Transfer-Encoding: chunked
2
{}
それに対してエラーがあった場合は以下の内容が返ります。
レスポンス内容(エラー時)
RPへのレスポンス内容の説明です。
HTTPステータス: 400(Bad Request) または 401(Unauthorized)
クエリパラメータ名 | 内容 |
---|---|
error | エラーコード |
error_description | エラーの詳細 |
エラー時は以下のようにRPに届きます。
HTTP/1.1 400 Bad Request
Date: Wed, 16 Oct 2024 07:34:51 GMT
Server: Restlet-Framework/2.3.4
Accept-Ranges: bytes
Vary: Accept-Charset,Accept-Encoding,Accept-Language,Accept
Content-Type: application/json
Connection: close
Transfer-Encoding: chunked
4a
{
"error_description":"Missing parameter: token",
"error":"invalid_request"}
おわりに
今回はOpenAMのRestAPIエンドポイントについて実例を示しながら、RPのアクセス方法について理解していく内容を記載しました。
RPを実装する際に一助になれば幸いです。
全5回に渡ってOpenID Connectについての記事を掲載しましたがいかがでしたでしょうか。