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.
Here's what we'll be using:
Let's get going.
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:
Once you have saved the integration, scroll down to Integration type and click on Public integration:
This will add a new section, OAuth Domain & URIs, which requires you to provide more data about your public integration.
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.
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.
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:
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.
That's the first step. Let's move on to create a new database to share with our integration later on.
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.
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.
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:
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:
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:
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:
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:
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.
Start by creating some example/dummy data:
example_data = {
"handle": "[@SomeHandle](/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:
We started by creating a public Notion integration and saved all the OAuth credentials
Continued with creating a table to which we would grant access.
Finally, we created the OAuth flow for users granting access to their pages and databases.
Lastly, we added data using the access token we received when a user granted our integration access to their pages and databases.
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
https://norahsakal.com/blog/automatically-organize-twitter-bookmarks-in-notion
Originally published at https://norahsakal.com/blog/create-public-notion-integration