Authorization

Integrations can be authorized for a single workspace or use OAuth to access multiple workspaces. Learn about implementing the right authorization for your integration.

Overview

The Notion API uses bearer tokens to authorize requests from integrations. As an integration developer, you'll need to choose the appropriate integration type for the integration you create. Based on the integration type, you'll receive and store bearer tokens differently. For both types, an integration must send the bearer token in the HTTP Authorization request header, as shown:

GET /v1/pages/b55c9c91-384d-452b-81db-d1ef79372b75 HTTP/1.1
Authorization: Bearer {MY_NOTION_TOKEN}

Integrations are granted access to resources (pages and databases) which users have shared with the integration. Once an integration has been added to a workspace, the user who added the integration can see it within Share menus inside Notion.

📘

Integrations have broad access to resources

When a user grants an integration access to a page or databases, the integration can read and write to that resource and its children. In the future, integrations may be allowed to request specific kinds of access (such as read-only) to give users more clarity and control.

Integration types

There are two types of integrations:

  1. Internal integrations are used to integrate the tools and services in use by you and your team in a way that's tailored to your people, workflows, and resources.
  2. Public OAuth integrations are used to build a product that is used by a broad audience, across many Notion workspaces.

By default, newly created integrations are internal integrations. After creation, the type can be changed to public integration in the integration settings.

Internal integrations are much simpler to develop. Public integrations require additional configuration and implement the client side of OAuth 2.0. Read on for details on how to implement authorization for each integration type.

Authorizing internal integrations

Internal integrations simply use a single integration token as the bearer token for all requests. In order to create an internal integration, you must choose an associated workspace. You must have Admin access level within the workspace you choose.

📘

Not an admin in your current workspace?

You can start building right now by creating a new personal workspace. Later, you can ask an admin to help you move the integration into another workspace. This may require using a different token, which is easy to do if you keep the token outside of source code using environment variables.

You can view the integration token later in the integration settings. This token is a secret. You should avoid storing it in your source code and avoid committing it in version control. Instead, we recommend reading the the token from an environment variable in your source code, and using a secret manager or deployment system to set the the token in the environment.

In each API request, send the token in the Authorization header as shown:

GET /v1/pages/b55c9c91-384d-452b-81db-d1ef79372b75 HTTP/1.1
Authorization: Bearer {MY_NOTION_TOKEN}

Authorizing public integrations

Public OAuth integrations receive an access token each time a user grants the integration access. The access token which is granted is associated with the user account that installed your integration. This process follows OAuth 2.0 using an authorization code grant, described in a few simple steps below.

The integration stores all the access tokens it receives (typically in a database) and chooses one as the bearer token for each request the integration sends to the Notion API.

Once a user has installed your integration, only that user will be able to interact with your integration in Notion. The installing user will be able to share additional pages and databases with your integration using the Share menu in Notion. Any additional user that wants to use your integration will need to go through the authorization process for themselves.

📘

During the Notion API public beta

We strongly recommend labeling your integration as "beta" or "preview" while the Notion API is in beta. This sets the right expectations with users as the API continues to evolve.

Currently, Notion does not review public integrations and does not list all public integrations in a directory. You may help users discover your integration by promoting it in your own product and in your marketing initiatives.

Prompting users to add an integration

The first step in the OAuth process is to request authorization from a user. This is done by sending a user to the authorization URL. You may send the user to this URL with a simple hyperlink or a redirect from another request.

The authorization URL is created using a few parameters. The URL begins with https://api.notion.com/v1/oauth/authorize and the parameters are added in the query string.

ParameterDescriptionRequired
client_idAn identifier for your integration, found in the integration settings
redirect_uriA URL where the user should return after granting access. This is described in detail below.
response_typeAlways use code
ownerAlways use user
stateIf the user was in the middle of an interaction or operation, this parameter can be used to restore state after the user returns. It is also can be used to prevent CSRF attacks.

As an example, the following hyperlink can be used to request authorization from a user:

<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>

🚧

Our OAuth process has changed as of September 21, 2021

Before September 21st, 2021, public integrations were installed at the workspace level by a workspace admin. We have updated this so that integrations are now installed at the user level, and can be installed by any Notion user, not just admins.

We recommend that any existing public integration add &owner=user to their Authorization URL as soon as possible to begin installing integrations at the user level.

On October 19th, 2021, all installations will begin to occur at the user level and any existing workspace-level integration will be migrated into a user-level integration belonging to the admin who installed that bot.

Please see our September 21st changelog for more details.

📘

Reauthorization

If a user who has already added the integration visits your authorization URL again and chooses the same workspace, that user may reauthorize the integration. During reauthorization, the page picker will not be shown. The access token received after exchanging the grant will be the same as the initial access token received.

User grants access

Once a user is sent to the authorization URL, they see a prompt to choose whether to grant the integration access or not.

Integration authorizationIntegration authorization

Integration authorization

If the user grants access, they are shown a page picker where they can search for and select pages and databases to share with your integration. Just like in the Notion app, users need Full Access permission to a page in order to share it with an integration, so the page picker will only show pages and databases for which the user has Full Access permission.

If the user allows access, they are redirected to the redirect_uri with a temporary authorization code (code).

Page pickerPage picker

Page picker

If the user denies access, they are redirected to the redirect_uri with an error (error).

Exchanging the grant for an access token

After the user grants access, the integration will receive an incoming request to the redirect_uri with the following information in the query string.

ParameterDescriptionRequired
codeA temporary authorization code
stateThe value provided by the integration when the user was prompted for access.

Finally, the integration exchanges the authorization code for an access token by sending an HTTP POST request to Notion's token URL: https://api.notion.com/v1/oauth/token. This request is authorized using HTTP Basic Authentication, using the integration's client_id and client_secret (found in the integration settings) to create a credential: {client_id}:{client_secret}. Please note, in HTTP Basic Authentication, the credentials are base64 encoded before adding to the Authorization header.

The body of the request contains the following JSON-encoded fields:

FieldTypeDescriptionRequired
"grant_type"stringAlways use "authorization_code"
"code"stringThe temporary authorization code received in the incoming request to the
"redirect_uri"stringThe "redirect_uri" that was provided in the Authorization step

The following is an example request to exchange the authorization code for an access token:

POST /v1/oauth/token HTTP/1.1
Authorization: Basic NDYzNTU4YTMtNzI1ZS00ZjM3LWI2ZDMtMDg4OTg5NGY2OGRlOnNlY3JldF95b3VfZm91bmRfbXlfZmFrZV9zZWNyZXQ=
Content-Type: application/json

{"grant_type":"authorization_code","code":"e202e8c9-0990-40af-855f-ff8f872b1ec6", "redirect_uri":"https://example.com/auth/notion/callback"}

Notion will respond to the request with an access token and some additional information. The response contains the following JSON-encoded fields:

FieldTypeDescriptionNot null
"access_token"stringAn access token used to authorize requests to the Notion API.
"workspace_id"stringThe ID of the workspace where this authorization took place.
"workspace_name"stringA human-readable name which can be used to display this authorization in UI.
"workspace_icon"stringA URL to an image which can be used to display this authorization in UI.
"bot_id"stringAn identifier for this authorization.
"owner"objectAn object containing information about who can view and share this integration. { "workspace": true } will be returned for installations of workspace-level tokens. For user level tokens, a user object will be returned.

Tips for storing and using access tokens

  • Store all of the information your integration receives with the access token. You never know when your UI requirements or product requirements might change, and you find some use of this data. It's really hard (or impossible) to send users to authorize again to get this information.
  • The bot_id returned along with your token should act as your primary key when storing information.
  • When storing this information in a database, build relations between this information and the resources in Notion that you are accessing. For example, if you store a Notion database or page ID, relate those records with the correct access token that you can use to authorize requests when reading or writing to that database or page.

Handling errors

Integrations should be prepared for two kinds of errors: user authorization failures and token request failures.

User authorization failures

User authorization failures occur when Notion cannot create an authorization code before redirecting back to the redirect_uri. This type of failure is normal - a user simply choosing not to approve the authorization request will trigger a failure. Integrations should be built to handle these cases gracefully.

In some cases, Notion sends the user back to the redirect_uri with additional error query parameter. Integrations should present the user with a helpful user interface. Notion uses the common error codes in the OAuth specification. In other cases, Notion shows the error to the user without redirecting. These are logical errors and should be remedied by updating the integration implementation.

Token request failures

Token request failures occur when the integration attempts to exchange the code grant for an access token, but something goes wrong. In these cases, the response contains a JSON-encoded body with an "error" field. Once again, Notion uses the common error codes from the OAuth specification.

Updated 3 days ago


Authorization


Integrations can be authorized for a single workspace or use OAuth to access multiple workspaces. Learn about implementing the right authorization for your integration.

Suggested Edits are limited on API Reference Pages

You can only suggest edits to Markdown body content, but not to the API spec.