0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

OAuth2.0/OpenID Connectの利用(5) :RPからアクセスするOpenAMのRestAPIエンドポイント

Last updated at Posted at 2024-10-16

はじめに

前回からだいぶ時間が空いてしましましたが、今回は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についての記事を掲載しましたがいかがでしたでしょうか。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?