I have been working with Notion’s API lately along with learning and regularly using Next.js. I wanted to start using Notion to track personal tasks along with tracking some metrics at work. But, I am a visual learner and need graphs to understand these databases I’m creating in Notion. This is where I needed to learn how to add Oauth to a project.
The plan is to create a Next.js application that users can login and “link” their notion account and customize and create charts for Notion Databases. For now, let’s focus on how to link your notion account.
Creating a Notion Integration
Before we can jump into the code, we first need to create a dev account and create a Notion Integration.
Create an account or login to Notion’s Dev Portal
Then Once you’ve logged in Click “Create Integration”
You’ll Need to create a private integration at first then we can move it to “public”
Setting up to make your integration public
Before we can make your integration public we need to do a couple things: create a website with a domain, create a private policy, create or use an email for support, and create a terms of use.
- Create a Boilerplate website within next.js that has the following pages
- Home page
- Private Policy
- Terms of Use page
- Deploy your website using your provider of choice. I am using Vercel to host this project.
Make your integration public
Once you have your website and email sorted out it’s time to convert your private Notion integration public.
We’ve filled in our links and email, now we need to add the callback OAuth email. I am using the /auth/notion-oauth
to handle the redirect URI.
Once you’ve submitted your integration, Notion will provide you with 3 strings:
- OAuth client ID
- OAuth client secret
- Authorization URL
Note: Since we’ll be developing this locally I created two integrations:
- “Production” that handles redirecting to my domain
- “Development” that handles redirecting to http://localhost:3000/auth/notion-auth
Jumping into the code
Taking those 3 strings from notion Let’s put them in our .env
file:
NEXT_PUBLIC_OAUTH_CLIENT_AUTHORIZATION_URI=<AUTHORIZATION URL>
OAUTH_CLIENT_ID=<OAUTH CLIENT ID>
OAUTH_CLIENT_SECRET=<OAUTH CLIENT SECRET>
First things first lets add a button that redirects the user to authorization URI
const handleConnectNotion = () => {
window.location.href = process.env.NEXT_PUBLIC_OAUTH_CLIENT_AUTHORIZATION_URI;
};
return (
<button onClick={handleConnectNotion}>Connect Your Notion Account {userEntry?.notionConnected && '(Connected)'}</button>
)
Once users click this button they’ll be redirected to a new window where they can login, link their notion account and link their pages.
Once the user clicks “Allow Access” they will be redirected back to the redirect URI. In this case the user will be directed to http://localhost:3000/auth/notion-oauth
. Let’s handle The redirected back to your URL.
Before we create a page we need to create a server-side function to fetch notion’s access token
'use server';
export async function handleNotionOAuth(code) {
const encoded = Buffer.from(`${process.env.OAUTH_CLIENT_ID}:${process.env.OAUTH_CLIENT_SECRET}`).toString('base64');
const redirectUri ="http://localhost:3000/auth/notion-oauth";
try {
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: 'authorization_code',
code: code,
redirect_uri: redirectUri,
}),
});
const responseJSON = await response.json();
if (responseJSON?.error) {
return { body: null, error: responseJSON?.error };
}
// add access token to DB
return { body: true, error: null };
} catch (error) {
return { body: false, error: error };
}
}
Create a page within app/auth/notion-oauth
. This page will handle the authorization code, and error and pass this information to the server-side function.
"use client"
import { useRouter } from 'next/navigation';
function Page() {
const [notionError, setNotionError] = useState(null);
const router = useRouter();
// url params
const error = searchParams.get('error');
const code = searchParams.get('code');
const handleNotionConnect = useCallback(async () => {
try {
const response = await handleNotionOAuth(code)
if (response?.error) {
setNotionError(true);
return;
}
setSuccess(true);
} catch (error) {
setNotionError(true);
} finally {
setLoading(false);
}
}, [code, user?.uid]);
useEffect(() => {
if (code) {
handleNotionConnect();
}
if(error){
setError(true);
};
}, [error, code, handleNotionConnect]);
if (notionError) {
return <h1>There was an error connecting your Notion account</h1>;
}
if (success) {
return (
<>
<h3>success! Forwarding you to your dashboard...</h3>
<Link href="/dashboard">
Back to dashboard
</Link>
</>
);
}
if (loading) {
return <h1>Loading...</h1>;
}
return (
<>
<h1>Notion OAuth</h1>
</>
);
}
Handling Access Token
Within your Server-side function you can taken responseJSON
and store it in your database. In this project I used Firebase
export async function handleNotionOAuth(code, userID) {
...
const responseJSON = await response.json();
if (responseJSON?.error) {
return { body: null, error: responseJSON?.error };
}
const notionRef = db.collection('users').doc(userID).collection("auth").doc("notion");
// add notion auth to firebase db /users/:user_id/auth/notion
await notionRef.setDoc(notionRef, responseJSON)
return {body: true, error: null};
}
You did it!
Congratulations! You’ve successfully connected Notion’s OAuth integration to your Next.js App!
Leave a Reply