1.はじめに
本稿はOAuth 2.0 Server PHPを使ってサーバー認証をやってみる。の続きです。本稿ではとりあえず作ったOAuth2.0 PHP Serverが外部からの呼び出し(ここではGoogleサービス)に対して適切に動作しているか確認してから、その上で動作するアプリ作成に入ろう、という目論みです。というか、Googleのドキュメントを追って行ったらいつの間にかGoogle OAuth2.0 Playgroundにさ迷いこんでいたというのが正直なところで、今となってはどこから入り込んだのか解りません。ただ、OAuth2.0サーバー認証のみの確認ができるので結果的にはとても良かったです。サービスアプリ(みたいなもの)を作ってからだと切り分けが面倒なことになっていたように思います。
作業の流れとしては次のようになります。
- Google OAuth2.0 PlaygroundをクライアントとしてOAuth2.0のリソースDBに登録する
- Google OAuth2.0 Playgroundに試験動作用の値を設定していく
- Google OAuth2.0 PlaygroundからOAuth2.0の認可をステップを追って実行する
環境の概要については先の「サーバー認証をやってみる。」をご参照ください。とりあえずここでは、OAuth2.0 Server PHP v1.10 (on PHP 8.1.10)とPosgreSQL環境で動作していることだけ触れておきます。
また、本稿におけるGoogle OAuth2.0 Playgroundの操作についてはあくまでも本稿作成時点のものとなります。
2.クライアントIDを登録する
google OAuth playgroundからのアクセス用クライアントを作成します。名前に制約はないようですが、本稿では'gpgclient'とします。client_secretは適当に(そして内密に)。scopeは'basic' REDIRECT_URIはhttps://developers.google.com/oauthplayground
を使います。
php -U phpoa2
psql (14.3)
"help"でヘルプを表示します。
phpoa2=> INSERT INTO oauth_clients (client_id, client_secret, redirect_uri, scope) VALUES ('gpgclient', '*****', 'https://developers.google.com/oauthplayground', 'basic');
INSERT 0 1
phpoa2=> select * from oauth_clients;
client_id | client_secret | redirect_uri | grant_types | scope | user_id
------------+---------------+------------------------------------------------------------+-------------+-------+---------
gpgclient | ***** | https://developers.google.com/oauthplayground | | basic |
(1 行)
phpoa2=> quit
3.Google OAuth 2.0 Playgroundから認可アクセスを試行する
Google OAuth2.0 Playgroundへ移動します。
手順としては次のようになります。
- OAuth2.0サーバ情報の設定
- 初回の認可動作
- 認可トークンの交換操作
- 交換されたトークンを使ったリソースへのアクセスを確認する
3.1.サーバ情報の設定
右上のOAuth 2.0 configuration(歯車アイコン)をクリックします。設定パネルが表示されるので、以下の要領で設定していきます。
- OAuth flowは
Server-side
- OAuth endpointsは
Custom
- Authorization endpointにはサーバとして作成した際の認証コントローラ(本稿ではauthorize.php)のURLに適当にstateパラメータをつける(値はなんでも良いようです)。
例)https://your.domain/authorize.php?state=xyz
- Access token locationは
Authorization header w/ Bearer prefix
- Token endpointに作成したトークンページ(token.php)のURI
- OAuth Client ID、OAuth Client Secretは2.で登録したidとsecretを設定
Close
をクリック。
3.2.初回の認可動作
左ペーンのテキストボックスにbasic
と入力して、Authorize APIs
をクリックすします。準備や設定に問題なければ、authorize.phpで作成した画面が表示されます。
このステップは、たぶんエラーが出やすいのではないかと思います。最初のうちはエラーなのかどうかも判断がつかないかもしれません(自分はそうでした)。404であれば解りやすいエラー(3.1.で設定したURIを確認してみてください)ですが、それ以外の表示だと、応答が一応帰ってきていて、サーバーにもエラーログは出ないので最初は戸惑いました。
3.2.1.出やすいエラー
- リダイレクトURLが妥当なものではない
{"error":"redirect_uri_mismatch","error_description":"The redirect URI provided is missing or does not match","error_uri":"http:\/\/tools.ietf.org\/html\/rfc6749#section-3.1.2"}
良く解らないけど、何か怒られていることは伝わってきます。
リソースDBのoauth_clientテーブルに2.で登録したクライアントIDに紐づけられているリダイレクトURIを確認してください。OAuth2.0 Playgroundではhttps://developpers.google.com/oauthplayground
になります。
念の為、ということであれば、ウェブサーバーのアクセスログを確認するのも良いかもしれません。authorize.phpを呼び出す際のパラメータredirect_url
に値が設定されています。 - Authorization Endpointにstateを付け忘れている
リダイレクトもできているのですが、レスポンスには認可コードが出ていないとおかしくて、良く見るとerrorパラメータが付いています。
HTTP/1.1 302 Found
Location: http://your.domain/authorize.php?scope=basic&redirect_uri=https%3A%2F%2Fdevelopers.google.com%2Foauthplayground&response_type=code&client_id=gpgclient&access_type=offline
GET /oauthplayground/?error=invalid_request&error_description=The+state+parameter+is+required HTTP/1.1
Host: developers.google.com
これはOAuth2.0サーバの情報設定時、Authorization EndpointのURIで最後にstateパラメータを付け忘れていると発生します。
3.3.認可キーをトークンと交換する
3.2.で設定に問題なければ、次のようなレスポンスが表示されます。3.2.1.のエラーパターン2と似通っていて紛らわしいですが、302 Foundがでてリダイレクトされた先のGETの応答にcode
とstate
パラメータが含まれているところが確認点です。
HTTP/1.1 302 Found
Location: http://your.domain/authorize.php?state=xyz&redirect_uri=https%3A%2F%2Fdevelopers.google.com%2Foauthplayground&response_type=code&client_id=gpgclient&scope=basic&access_type=offline
GET /oauthplayground/?code=8f3d83371d296fc9931a483f3b7c2056150bafbb&state=xyz HTTP/1.1
Host: developers.google.com
左側に表示されているStep 2 Exchange authorization code for tokens
をクリックします。Authorization code
には、Step 1を実行したときのRequest / Responseで表示されたGET /oauthplayground/?code=から&stateまでの文字列が設定されているはずです。設定されていることを確認したらExchange authorizatio code for tokens
をクリックします。
HTTP/1.1 200 OKが戻り、以下のようにaccess_tokenが戻れば大丈夫です。
{
"access_token": "724a86278ec7ca80a1ef6918a1976ba2ed40d7d7",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "01e4ddd9f2d6ae1695ac2c8573b25eac075bc952",
"scope": "basic"
}
3.3.1.出やすいエラー
最初の認可処理で返されたコードは30秒で期限切れになります。期限がきれた状態だとアクセストークンとの交換は失敗します。
HTTP/1.1 400 Bad Request
Content-length: 82
X-powered-by: PHP/8.1.10
Server: Apache/2.4.54 (Fedora Linux) PHP/8.1.10 OpenSSL/3.0.5
Connection: close
Cache-control: no-store
Date: Tue, 18 Oct 2022 09:27:48 GMT
Content-type: application/json
{
"error_description": "The authorization code has expired",
"error": "invalid_grant"
}
期限が切れてしまった場合はStep.1から繰り返せば大丈夫です。
3.4.交換されたトークンを使ったリソースへのアクセスを確認する
Step.2でアクセストークンを得られたら、Step 3 Configure request to API
をクリックします。このステップでアクセスするのは前稿で作成したリソース制御ページ(resource.php)になります。
- HTTP Methodは
GET
- Request URI
https://your.domain/resource.php
Send the request
をクリックする。
responceにresource.phpの実行結果が表示されます。前稿の要領でresouce.phpを作成していると次のような出力になると思います。
HTTP/1.1 200 OK
Content-length: 90
Content-location: https://your.domain/resource.php
X-powered-by: PHP/8.1.10
Keep-alive: timeout=5, max=100
Server: Apache/2.4.54 (Fedora Linux) PHP/8.1.10 OpenSSL/3.0.5
Connection: Keep-Alive
Date: Tue, 18 Oct 2022 09:31:08 GMT
Content-type: text/html; charset=UTF-8
{"success":true,"message":"You accessed my APIs!"}
最後の{"success":true,"message":"You accessed my APIs!"}が出力されていることを確認します。
4.さいごに
本稿で、Googleサービスからの認可動作には対応できたことが確認できました。次稿からGoogle Home Assistantアプリ(というのか、サービスと言うべきなのか)の作成に入りたいと思います。最初はGoogle Developerのドキュメントを見ながら、簡単なモックアップの作成から始めようと考えています。