Skip to main content

How to create a public Notion integration

Β· 8 min read
Norah Sakal

Cover image

If you're struggling with creating public Notion integrations and getting access to other users' Notion databases, this tutorial is for you.

With this walk-through, you'll be able to authenticate users, get their access token, and add data to the database they've shared with your public Notion integration.

Dependencies​

Here's what we'll be using:

1. Python πŸβ€‹

2. Notion API πŸ“β€‹

Steps​

1. Create public Notion integration​

2. Create a table to share​

3. Create Notion Auth 2.0 authorization flow​

4. Add data to an authorized table​

Let's get going.


1. Create public Notion integration​

Let's start with creating a public Notion integration.

Start creating an integration by logging into your Notion account, going to https://www.notion.so/my-integrations, and clicking on the + New integration button.

Give your integration a name and select the workspace where you want to install this integration. We'll upgrade the integration to use OAuth later.

Then choose the capabilities that the integration will have. Lastly, click Submit to create the integration:

Create integration

Once you have saved the integration, scroll down to Integration type and click on Public integration:

Choose Public integration

This will add a new section, OAuth Domain & URIs, which requires you to provide more data about your public integration.

OAuth section

Let's go ahead and add all the required data, starting with Redirect URIs. As it says in Notion:

In the Notion OAuth flow, users will be redirected to this path after they have authenticated with Notion. The path will be appended with the authorization code for access and must have a protocol. It can’t contain URL fragments, relative paths or wildcards, and can’t be a public IP address. It must also be included in the token request.

Add Redirect URI

For learning, this tutorial will copy the authorization code right from the browser URL. But for your production app, you'll need to provide a redirect URL where you can extract the authorization code from your users.

Continue with adding your Company name and your Website or homepage - this website/homepage will be used in your integration page as stated by Notion:

Used to link to your integration’s website or homepage in your integration page and authentication screens.

Add company name and website

Further, fill out a tagline and go ahead and add the links to a privacy policy, terms of use, and finally, a support email. All these fields are required because you're about to create a public integration available to all Notion users.

When you've filled out all the fields, click on Submit:

Add support details and terms

Make sure to save the OAuth client ID, OAuth client secret, and Authorization URL for the next steps. Remember that you'll only be able to reveal the OAuth client secret once, so make sure to save it somewhere for the next step.

OAuth credentials

That's the first step. Let's move on to create a new database to share with our integration later on.

2. Create a table to share​

This step is to create a new database that we'll authorize our public integration to access.

Let's create a table with 2 columns, handle and tweet:

Choose text as the type for the column tweet. As you might guess - this is a table we'll populate with tweets later as a use case example. Name the table Twitter.

Create a new database

That's all we need for this database. Let's head to the next section, where we'll create the Notion 2.0 authorization flow for users.

3. Create Notion Auth 2.0 authorization flow​

In this section, we'll write to code needed to generate

1) a URL that grants your public integration access to chosen databases/pages and

2) an access token from the code we'll receive in the authorization redirect

Start by importing all the libraries and creating variables for your API keys that we received in Notion in step 1:

OAuth credentials

import base64
import json
import os
import requests
import urllib.parse

oauth_client_id = "YOUR_OAUTH_CLIENT_ID"
oauth_client_secret = "YOUR_OAUTH_CLIENT_SECRET"
redirect_uri = "YOUR_REDIRECT_URL"

Parse your redirect URL:

parsed_redirect_uri = urllib.parse.quote_plus(redirect_uri)

The next step is to create the authorization URL that authorizes your public integration access to users' pages/databases:

auth_url = f"https://api.notion.com/v1/oauth/authorize?owner=user&client_id={oauth_client_id}&redirect_uri={parsed_redirect_uri}&response_type=code"
print(auth_url)

This link will prompt users to authorize your public integration and give you access to their chosen Notion pages and databases.

Click on the link and then Select pages. Here's what you and the user sees when visiting your URL:

Auth link

If the user grants access, they will be shown a page where they can search and pick which pages and databases they want to share with your integration.

Now pick the Notion database that we created earlier, it should be called Twitter, this is what you should be seeing:

Auth link

Click on Allow access and you should be redirected to your redirect_uri.

If users allow access, they'll also be redirected to your redirect_uri with a temporary authorization code. It will look something like this:

https://YOUR_REDIRECT_URL/?code=9ac813er-34ad-4ba9-a5a0-1246ee085f86&state=
|--- Your redirect URL --| |--- The temporary authorization code ---|

Save the whole URL that you just got redirected to after allowing authorization:

redirect_url_response = "THE_URL_YOU_GOT_REDIRECTED_TO_AFTER_AUTHORIZATION"

Then extract and save the code you receive in the redirect URL:

auth_code = redirect_url_response.split('code=')[-1].split('&state=')[0]
auth_code

After the user grants access, we need to exchange 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.

The request is authorized with HTTP Basic Authentication, so you'll need to base64 encode your integration's credentials first:

key_secret = '{}:{}'.format(oauth_client_id, oauth_client_secret).encode('ascii')
b64_encoded_key = base64.b64encode(key_secret)
b64_encoded_key = b64_encoded_key.decode('ascii')

The last step in this authorization flow is to exchange the temporary code for an access token:

base_url = 'https://api.notion.com/v1/oauth/token'

auth_headers = {
'Authorization': 'Basic {}'.format(b64_encoded_key),
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
}

auth_data = {
'grant_type': 'authorization_code',
'code': auth_code,
'redirect_uri':redirect_uri,
}

auth_resp = requests.post(base_url, headers=auth_headers, data=auth_data)
auth_resp.json()

Notion will respond to the request with an access token and some additional information.

Here's what the response looks like:

Access token response

Store all of the information your integration receives with the access token. You can now use this access token to reach all the pages and databases the user granted access to.

Start by searching for which databases the user granted access to:

url = "https://api.notion.com/v1/search"

payload = {"page_size": 100}
headers = {
"accept": "application/json",
"Notion-Version": "2022-06-28",
"content-type": "application/json",
"authorization": f"Bearer {access_token}"
}

response = requests.post(url, json=payload, headers=headers)

Here's what the response looks like:

Database search response

Save the database id for when you want to add data in the next step:

database_data = response.json()['results']
notion_database_id = database_data[0]['id']

Great, now we have all the logic to ask users to grant access to their pages and databases in Notion. The last step is adding data to the table the user gave you access to.

4. Add data to an authorized table​

Start by creating some example/dummy data:

example_data = {
"handle": "@SomeHandle",
"tweet": "Here is a tweet"
}

Then add the data to the authorized Notion database:

headers = {
'Authorization': 'Bearer ' + access_token,
'Content-Type': 'application/json',
'Notion-Version': '2021-08-16'
}

payload= {
'parent': { 'database_id': notion_database_id },
'properties': {
'title': {
'title': [
{
'text': {
'content': example_data['handle']
}
}
]
},
'tweet': {
'rich_text':[
{
'type':'text',
'text': {
'content': example_data['tweet']
}
}
]
}
}
}

response = requests.post('https://api.notion.com/v1/pages', headers=headers,data=json.dumps(payload))

If we go back to the Notion database we created in step 2, you'll see the input we just made added to the database:

Notion database input


Summary​

1. Create public Notion integration​

We started by creating a public Notion integration and saved all the OAuth credentials

2. Create a table to share​

Continued with creating a table to which we would grant access.

3. Create Notion Auth 2.0 authorization flow​

Finally, we created the OAuth flow for users granting access to their pages and databases.

4. Add data to an authorized table​

Lastly, we added data using the access token we received when a user granted our integration access to their pages and databases.


Next steps​

Repo with source code​

Here is the repo with a Jupyter notebook with all the source code if you'd like to implement this on your own ⬇️
https://github.com/norahsakal/create-public-notion-integration


How to create an automated Twitter bookmark organizer in Notion​

https://norahsakal.com/blog/automatically-organize-twitter-bookmarks-in-notion