Unique access tokens per OAuth authorization (Changelog 6/8) : hkob の雑記録 (535)

はじめに

hkob の雑記録の第535回目(連続111日目)は、Developer ChangeLog の 6/8 版を解説します。しばらく忙しくて情報収集できていなかったので、5つほど溜まってしまいました。今日から一つずつ紹介していきます(忙しくてブログを書いている時間がないので小出しにさせてください)。

Unique access tokens per OAuth authorization

以下のように 6/8 に ChangeLog が更新されています。

Changelog 6/8

新しいパブリック接続では、OAuth 認可が成功するたびに、既存の有効なトークンを返すのではなく、新しい access_tokenrefresh_token が発行されるようになりました。既存の接続は従来どおりの挙動を維持します。Authorization guide に記載のとおり、同じ接続を再認可した場合も含め、成功レスポンスごとに返ってくるトークンペアを必ず保存してください。

これまで public integration では、OAuth において既存の有効なトークンが返されていたそうです。既存の接続は互換性のためにそのまま維持されるそうですが、今後は access_tokenrefresh_token が必要になるようです。Authorization guide に記載があるそうなので、そちらを確認してみましょう。引用すると表などが表示できなので、このまま翻訳文書を貼り付けます。

ステップ 5 - 接続が今後のリクエストのために access_tokenrefresh_token を保存する

接続が受け取る access_tokenrefresh_token の両方を保存する方法を用意します。 access_token は Notion API への認可済みリクエストに使用され、 refresh_token は新しい access_token を生成するために使用されます。

トークンアクセスの保存と利用に関するヒント

  • アクセストークンを保存する一般的な方法は、データベースを用意することです。データベースを使用する場合は、access_tokenrefresh_token、およびそのトークンで接続がアクセスする対応する Notion リソースの間にリレーションを構築してください。たとえば、Notion データベース ID やページ ID を保存する場合、そのデータベースやページを読み書きするリクエストの認可に使用する正しい access_token と、継続的なトークンライフサイクルを支える refresh_token を、それらのレコードに関連付けます。
  • 接続が access_tokenrefresh_token とともに受け取るすべての情報を保存してください。UI やプロダクト要件が将来どのように変わり、このデータが必要になるかは分かりません。ユーザーに認可フローを再実行してもらい、その情報を再生成することは非常に困難、または不可能です。
  • トークンとともに返される bot_id は、その認可に対応する Notion ボットを識別します。成功した各認可レスポンスからトークンペアを保存してください。これには、同じ接続を再認可した場合も含まれます。その場合、Notion が新しい access_tokenrefresh_token を返す可能性があります。

ステップ 6 - アクセストークンを更新する

アクセストークンを更新すると、新しいアクセストークンと新しいリフレッシュトークンが生成されます。ステップ 4 で提供された refresh_token を、Notion のトークンエンドポイントへの POST リクエストの一部として送信します。 https://api.notion.com/v1/oauth/token

このエンドポイントの詳細は、API リファレンスドキュメントの refreshing a token に記載されています。リクエストは HTTP Basic 認証を使用して認可されます。認証情報は、接続の CLIENT_IDCLIENT_SECRET をコロンで区切って組み合わせたものです。形式は次のとおりです。

CLIENT_ID:CLIENT_SECRET

これらの値はどちらも Developer portal で確認できます。HTTP Basic Authentication では、認証情報は base64 でエンコードされたうえで Authorization ヘッダーに追加されます。リクエスト本文には、次の JSON エンコードされたフィールドを含めます。

フィールド 説明 必須
"grant_type" string 常に "refresh_token" を使用します。
"refresh_token" string 認可ステップで返された "refresh_token"

以下は、 refresh_token を新しいアクセストークンと新しいリフレッシュトークンに交換するリクエスト例です。

HTTP

POST /v1/oauth/token HTTP/1.1
Authorization: Basic "$CLIENT_ID:$CLIENT_SECRET"
Content-Type: application/json

{"grant_type":"refresh_token","refresh_token":"nrt_4991090011501Ejc6Xn4sHguI7jZIN449mKe9PRhpMfNK"}

この例を Node.js で書くと、次のようになります。

JavaScript

const clientId = process.env.OAUTH_CLIENT_ID;
const clientSecret = process.env.OAUTH_CLIENT_SECRET;

// base64 でエンコード
const encoded = btoa(\${clientId}:${clientSecret}`);

const response = await fetch("https://api.notion.com/v1/oauth/token", {
    method: "POST",
    headers: {
    Accept: "application/json",
    "Content-Type": "application/json",
    Authorization: `Basic ${encoded}`,
},
    body: JSON.stringify({
        grant_type: "refresh_token",
        refresh_token: "your-refresh-token",
    }),
})

おわりに

個人的には public integration を使っていないので影響はないのですが、他人にアプリを提供している人などは対応が必要となるかもしれませんね。

https://hkob.notion.site/hkob-16dd8e4e98ab807cbe3cf3cc94cdfe0f?pvs=4