Authorization(オーソリゼーション) ~後半~

この記事は、Notion APIドキュメントを日本語訳し、筆者の言葉で非開発者でも理解できるよう編集したものです。

なお本記事は「Authorization」のページについての解説です。

また基本的な専門用語等の説明については、その言葉の定義や概念が複雑な場合、または文章の前後を理解するにあたって説明が必要であると判断した場合など、筆者の判断にて補足として記載することとしています。

なお、本記事は Authorization(オーソリゼーション) ~前半~ に続くSTEP2以降の内容です。

非開発者のかたであれば、前回の記事「Authorizationの構築 ~前半~」の内容を把握していないとこの記事の内容は理解できないと思います。
よって必ず前回の記事を読み(できればその前も)、正しい手順を踏んでから本記事の内容に臨むことを強くオススメします。

STEP2:パラメーターを受け取る

ユーザーがオーソリゼーションを完了すると、Notionはインテグレーションに設定したリダイレクトURIにパラメーターを追加します。(ユーザーのブラウザ画面は、パラメーターが追加されたリダイレクトURIに遷移します。)

開発者であるあなたは、そのURIに追加されたパラメーターを取得しなければいけません。

Notionが返すパラメーターの受け取りかた

Notionの公式ドキュメントでは、パラメーターを受け取る際のプログラムをReactで解説しています。
ReactとはJavaScriptのライブラリであり、開発初心者がすぐに覚えなければいけない技術ではありません。

この記事では理解を促すことを優先していますので、サーバーサイドに置く簡単なPHPによる方法をご紹介します。

#PHP
<?php if (isset($_GET['code'])) { // もし、リダイレクトURIに「code」があったら…… $code = $_GET['code']; // codeを取得して変数に格納しろ // あとでこの行には重要な処理を書きます!! } ?>

上記はリダイレクトURIに返されたcodeを受け取るだけのコードです。
受け取るというか、上記のリダイレクトURIからcodeを抽出しているというのが正しい表現です。

ともあれ、codeを受け取るだけなので何も起こりません。
受け取るだけなので超簡単なコードでできますが、これはサーバーサイドのプログラムです。
クライアントサイド(ブラウザ側)でもcodeを取得できますが、セキュリティの点で絶対やめたほうが良いです。

上記のコードをphpファイルとしてサーバーにアップロードしましょう。
筆者はファイル名を「auth.php」としましたので、同じようにしていただいても構いません。(以降、ファイル名を出すときは「auth.php」とします)

STEP3: codeを投げてアクセストークンをもらう

STEP2で受け取ったcodeは、あくまでSTEP3以降で使用する一時的なパラメーターです。
続いてcodeをNotionへPOST(送ること)する必要があります。

このあたりまでくると「これは今、何をやってるフェーズなんだ?」と混乱するかたもいらっしゃるかもしれません。
よってもう一度、全体的なフロー図を元に説明します。(理解しているかたは読み飛ばしてください。)

オーソリゼーションのフロー図

③で正式なアクセストークンがNotionからレスポンスされています。
STEP3はアクセストークンを取得する条件である「②codeやシークレット情報をNotionに送る」というフェーズにあたります。

つまりSTEP3は、Noionの「アクセストークンよこせだと?誰だお前は!」という問いに対し、「私はこういう者です。code:xxxxxxxx client_id:yyyyyyyy client_secret:zzzzzzzz」という回答を投げるというプロセスの構築です。

このプロセスが正常に実行されることで、Notionは「話は聞いている。アクセストークンだったな。少し待ってろ。」とアクセストークンを送ってきてくれます。

では実際に、codeやシークレット情報をPOSTするプログラムを書きます。

先ほどcodeを受け取るコードを紹介しましたが、「// あとでこの行には重要な処理を書きます!!」という部分に、codeをPOSTするコードを追加するだけです。

<?php if (isset($_GET['code'])) { // もし、リダイレクトURIに「code」があったら…… $code = $_GET['code']; // codeを取得して変数に格納しろ // パブリックインテグレーションの各情報 $client_id = 'インテグレーションのクライアントID'; $client_secret = 'インテグレーションのクライアントシークレット'; $redirect_uri = 'サーバーにアップロードしたPHPのURL'; $auth_header = "Authorization: Basic " . base64_encode("$client_id:$client_secret"); // **base64エンコードしたHTTPベーシック認**証用のヘッダーを作成 // POSTデータをJSON形式にエンコード $data = json_encode(array( 'grant_type' => 'authorization_code', 'code' => $code, 'redirect_uri' => $redirect_uri )); // HTTPリクエストに必要な情報を設定 $options = array( 'http' => array( 'method' => 'POST', 'header' => "Content-Type: application/json\r\n" . $auth_header, 'content' => $data ) ); $url = 'https://api.notion.com/v1/oauth/token'; // NotionにPOSTするURL $context = stream_context_create($options); // optionsに格納した情報をコンテキストにする $response = file_get_contents($url, false, $context); // コンテキストをPOSTしてレスポンスを取得 } ?>

コードの各行の内容はコメントアウト(コード内の解説)を参照していただくとして、詳しい説明は省略します。
ただ、非開発者だと何のことやらわからなさそうな部分だけ解説します。

$auth_header = "Authorization: Basic " . base64_encode("$client_id:$client_secret"); // **base64エンコードしたHTTPベーシック認**証用のヘッダーを作成

トークンエンドポイントに送るPOSTリクエストは、base64エンコードされた認証情報にてHTTPベーシック認証を行うことで実現します。
HTTPベーシック認証で送るクライアントIDとクライアントシークレットは、以下のような形式で送ることになります。

CLIENT_ID:CLIENT_SECRET

……。

はい、なに言ってるかわからないですね。以下で説明します。


ご自身のインテグレーションのクライアントIDやクライアントシークレットを見てみてください。 数字と英字の入り混じったワケのわからない文字になっていると思います。

このワケのわからない文字を普通のテキストに変換して、認証時の情報として読み取れるようにするのがbase64エンコードです。

ともあれ上記のコードでは、インテグレーションの各情報やHTTPベーシック認証用のヘッダーなどを連想配列という形にして$optionsという変数に格納しています。

最後に、Notionの公式ドキュメントでも案内されているトークンエンドポイント($url = 'https://api.notion.com/v1/oauth/token';という部分)に各情報をPOSTしてSTEP3が完了します。(トークンエンドポイント=認証情報を送る場所)

※$optionsをコンテキストにして送っていますが、これは本記事の補足として最後に説明します。

STEP4:Notionから返されるアクセストークンを取得する

さて、オーソリゼーションもSTEP4が最後と言えば最後です。

本当は実際にAPIを利用するにあたって、取得するアクセストークンをデータベースなりjsonファイルなりで保存して再利用しなければいけません。
ただ当ブログでは、オーソリゼーションによるアクセストークンの取得までをいったんの区切りといたします。
(※アクセストークンの保存方法やAPIの使用目的は、人により好みや方向性が異なるためです。)

アクセストークンを取得するPHPコード

実は、アクセストークンを取得するコードはSTEP3で紹介したコードに実装されています。
最後の行にあった以下のコードです。

$response = file_get_contents($url, false, $context); // コンテキストをPOSTしてレスポンスを取得

つまりSTEP3に書いたコードにより、「認証 → codeの取得 → codeをPOST → アクセストークンの取得」というプロセスは完了しているのです。

ただ非開発者としての立場を想像するに、「どんな感じのどんなものが返されてるの?」というところを視覚的に確認しないと理解できないかたもいらっしゃると思います。

よってこの章では、「POSTしたcodeと取得したアクセスコード画面に表示させる」というところまでをコードに実装したいと思います。

以下のコードは、先ほどまで書いていたコードにアクセスコードなどを画面に表示する命令文を追加したものです。

<?php if (isset($_GET['code'])) { // もし、リダイレクトURIに「code」があったら…… $code = $_GET['code']; // codeを取得して変数に格納しろ // パブリックインテグレーションの各情報 $client_id = 'インテグレーションのクライアントID'; $client_secret = 'インテグレーションのクライアントシークレット'; $redirect_uri = 'サーバーにアップロードしたPHPのURL'; $auth_header = "Authorization: Basic " . base64_encode("$client_id:$client_secret"); // base64エンコードしたHTTPベーシック認証用のヘッダーを作成 // POSTデータをJSON形式にエンコード $data = json_encode(array( 'grant_type' => 'authorization_code', 'code' => $code, 'redirect_uri' => $redirect_uri )); // HTTPリクエストに必要な情報を設定 $options = array( 'http' => array( 'method' => 'POST', 'header' => "Content-Type: application/json\r\n" . $auth_header, 'content' => $data ) ); $url = 'https://api.notion.com/v1/oauth/token'; // NotionにPOSTするURL $context = stream_context_create($options); // optionsに格納した情報をコンテキストにする $response = file_get_contents($url, false, $context); // コンテキストをPOSTしてレスポンスを取得 if ($response === FALSE) { // エラー処理:アクセストークンの取得に失敗した場合 $error_message = error_get_last(); // 最後に発生したエラーを取得 echo 'アクセストークンの取得に失敗しました。エラーメッセージ: ' . print_r($error_message, true); } else { // アクセストークンの取得に成功した場合 $data = json_decode($response); $access_token = $data->access_token; // POSTデータとアクセストークンを表示 echo '<p>POSTデータ(code): ' . htmlspecialchars($code) . '</br>'; echo '<p>アクセストークン: ' . htmlspecialchars($access_token) . '</br>'; } } ?>

if ($response === FALSE) { というところから下が追加したコードです。

こちらも詳しい解説は省略します。

一応、簡単に説明すると「codeやシークレット情報をPOSTした結果、エラー情報が返ってきたらエラーメッセージを表示して、正常にレスポンスされたらPOSTしたcodeとアクセストークンを表示する」というロジックが組まれています。

試しに、正常にレスポンスされたときとエラーが返ってきたときの違いを見てみましょう。

【正常時】
正常にレスポンスされたときの画面
続いて、インテグレーション情報を以下のようにして、認証を行ってみました。
$client_id = 'aaaaaaaaaaaaaaa';
$client_secret = 'bbbbbbbbbbbbb';
$redirect_uri = 'cccccccccccc';

【エラー】
エラー画面

「君、auth.phpの32行目にあるfile_get_contentsでなんか送ってきたけど、内容が間違っとるで」という内容です。
「401」と出ていますが、HTTPリクエストによる401エラーは「Unauthorized(未認証)エラー」と言うそうで、「ログインIDとかパスワードとかの情報が間違ってるから、必要な情報へのアクセス権を与えません」というものです。

さて、最後に気になるのが「テンプレートがユーザーのアカウントに複製されたか」ですが、このとおり。

ユーザーのアカウントに複製されたテンプレート

テスト用に作成したアカウントにばっちり複製されていました。
あとは私も1週間の献立を考えて、API経由で献立を追加していけばよいだけですね。
刺身とかラーメンとかの日があってもいいんじゃないかと思いました。

オーソリゼーションの補足とまとめ

Notionの公式ドキュメントでは、オーソリゼーションのページがSTEP4、STEP5まであります。

重ねて申し上げますが、当ブログは「非開発者がNotion APIを理解する」ということが最大の目的です。

STEP4では、codeをPOSTした後に返るアクセストークンだけでなく、API利用時にレスポンスされる様々なフィールド(パラメーター)が紹介されています。
またSTEP5では、「受け取ったアクセストークンは大事に保存してAPI利用時に使うんやで。アクセストークン失くしたからって、何度もユーザーが認証操作してくれると思うなよ?」ということが書かれています。

しかし、非開発者は私を含めてOAuthそのものの理解が浅く、オーソリゼーションがどのようなプロセスと動きで実行されるのかというイメージすら定着していません。

よって本ブログでは、オーソリゼーション後のアクセストークン取得までを解説させていただきました。

以降の手順については、筆者が開発に必要とした部分を抜粋しながら記事として追加していく予定です。

また、改めてお伝えしたい事項があります。

本記事を含め、オーソリゼーションの解説にあたり、セキュリティの観点から行うべきではない、または書くべきではない情報をコードの中に含めています。
これは非開発者がオーソリゼーションの動きを簡単に確認するための手段であり、本番運用にあたってはセキュリティリスクを低減する方法を必ず実装していただくよう重ねてお願い申し上げます。

Next Post Previous Post