アルパカログ

開発しているNotion Blogやプログラミングの話題が中心のブログ

Notion パブリックインテグレーションの認可を実装する

Notion APIを利用するにはインテグレーションを作成・追加する必要があります。

Notion APIの説明ではInternal Integrationsを使った例がよく見られる一方で、Public Integrationsを使った例は比較的少ないように思います。

そこでこの記事ではInternal IntegrationsとPublic Integrationsの違いを説明し、OAuth 2.0に則ったPublic Integrationsの認可の実装方法を説明します。

Internal Integrationsとは?

Internal IntegrationsはNotionワークスペースの管理者だけが追加できます。APIでアクセスできるのはワークスペースのうち、インテグレーションに接続されたページもしくはデータベースです。

Internal Integrationsは自作ツールを個人のワークスペースで利用したり、社内ツールを会社のワークスペースで利用するケースで便利です。

一方、アプリやサービスを公開し、不特定多数のユーザーにそれぞれのワークスペースでAPIを利用させたいケースには不向きです。こういったケースではPublic Integrationsを利用します。

Public Integrationsとは?

Public Integrationsはいわゆるアプリ連携で、例えばみなさんもTwitterやGmailなどのサービスと連携するタイプのアプリやサービスを使ったことがあるかもしれません。

「以下の情報をアプリに提供します。よろしいですか?」のような画面を見たことがあれば、まさにそれです。

Public Integrationsを使うことで、ユーザーにNotion APIを利用するアプリやサービスが提供できるようになります。

Internal Integrationsは管理者が自身の管理するワークスペースへインテグレーションを追加して利用するため、何が起こったとしても自己責任の範囲内だと言えます。

一方、Public Integrationsはユーザーがアプリやサービス(=開発者)を信用して自身のワークスペースへインテグレーションを追加します。

ひとたびインテグレーションが追加されると、アプリやサービスはユーザーのNotionデータへアクセスできるようになります。

そのため、Public Integrationsを追加する際にはどんなデータが必要なのか、権限は何かといったこと明示しユーザーの許可を得る必要があります。当然、実装はInternal Integrationsよりも複雑になります。

OAuth 2.0に則ったPublic Integrationsの認可処理の実装

NotionインテグレーションはデフォルトではInternalなのでPublicに変更します。

設定画面のUIは頻繁に変わるため、公式ドキュメントを参照して OAuth client ID, OAuth client secret, Authorization URL を得るところまで進めてください。

アプリやサービスでNotionページのテンプレートを提供したい場合は、インテグレーションのページで “Notion URL for optional template” を設定しておきます。

テンプレートページはWebに公開されている必要があります。また、URLは内部URLではなく公開URLでなければならないため、共有メニューからURLを取得しましょう。

image block

Authroization URL を入手したら a タグなどでユーザーが遷移できるようにします。

<a href="https://api.notion.com/v1/oauth/authorize?owner=user&client_id=463558a3-725e-4f37-b6d3-0889894f68de&redirect_uri=https%3A%2F%2Fexample.com%2Fauth%2Fnotion%2Fcallback&response_type=code">Add to Notion</a>
aタグなどでユーザーをAuthorization URLに遷移させる

OAuth client ID, OAuth client secret は秘匿情報として環境変数などにセットしておきます。

上記の遷移先で許可・不許可の操作後、ユーザーはRedirect URIsで指定したURLにリダイレクトされてきます。

許可の場合は code が、不許可の場合は error がクエリパラメータに付加されています。不許可の場合はアプリ側で適切に処理します。

code を受け取ったら今度は https://api.notion.com/v1/oauth/token に対して必要なデータを必要なフォーマットでPOSTリクエストします。

必要なデータは下記のフィールドを持つJSONです。

Field Type Value
grant_type string "authorization_code"
code string リダイレクトURLで受け取ったパラメータ
redirect_uri string インテグレーションに設定したRedirect URIsのURL

また、リクエストヘッダーに下記のヘッダー情報を付加します。

  • Authorization: Basic $CLIENT_ID:$CLIENT_SECRET
  • Content-Type: application/json

ここで $CLIENT_ID:$CLIENT_SECRETOAuth client IDOAuth client secret: で接続してBase64エンコーディングした文字列です。 : で単に接続しただけではエラーになってしまうので注意してください。

Node.js (バージョン18以上)のコード例を下記に示します。

const credentials = Buffer.from(
  `${NOTION_OAUTH_CLIENT_ID}:${NOITON_OAUTH_CLIENT_SECRET}`
).toString('base64')

const res = await fetch('https://api.notion.com/v1/oauth/token', {
  method: 'POST',
  headers: {
    Authorization: `Basic ${credentials}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    grant_type: 'authorization_code',
    code: code,
    redirect_uri: redirectURI.toString(),
  }),
})

const data = await res.json()
if (data.error) {
  throw new Error(data.error)
}
codeをPOSTするコード例

成功すると下記のデータがJSONでレスポンスされます。

アクセストークン以外の情報もありますが、これらのデータはこのタイミングでしか得られないため、全てデータベースなどの永続ストアに保存します。

Field Type Desc
access_token string アクセストークン
bot_id string 認可ID
duplicated_template_id string インテグレーションで提供したテンプレートから新しく作られたページのID。テンプレートが提供されていない場合は null
owner object インテグレーションを閲覧、共有できるユーザーまたはワークスペースの情報
workspace_icon string ワークスペースアイコンのURL
workspace_id string ワークスペースID
workspace_name string ワークスペース名

以上です。

この記事ではInternal IntegrationsとPublic Integrationsの違いを説明し、OAuth 2.0に則ったPublic Integrationsの認可の実装方法を説明しました。