←Back

Create & Connect Notion OAuth to Next.js application

notion + nextjs image

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”

Notion My Integrations

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.

  1. Create a Boilerplate website within next.js that has the following pages
    • Home page
    • Private Policy
    • Terms of Use page
  2. 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.

notion organization information
private policy and terms of service page for notion integration

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.

OAuth domain and URI's for notion

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:

  1. Production” that handles redirecting to my domain
  2. Development” that handles redirecting to http://localhost:3000/auth/notion-auth
my integrations page of notion

Jumping into the code

Taking those 3 strings from notion Let’s put them in our .env file:

Plaintext
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

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

first OAuth page for notion
select pages in notion OAuth page

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

JavaScript
'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.

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

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

2 responses to “Create & Connect Notion OAuth to Next.js application”

  1. Patsy Fraley Avatar
    Patsy Fraley

    I needed to thank you for this fantastic read!!
    I certainly enjoyed every little bit of it. I’ve got you book marked to look at new things you post…

  2. Mehdi Avatar
    Mehdi

    Amazing, thanks a lot

Leave a Reply

Your email address will not be published. Required fields are marked *