GuidesDatabase
Table of Contents:
MongoDB
Setup
- Create a new project and deploy a cluster on MongoDB Atlas
- In your project on MongoDB Altas, click [Network Access] then [+ Add IP Address]. Enter
0.0.0.0/0
in [Access List Entry]. This allows connections from your computer and your production deployment(s) (Vercel for instance). - If you haven't done it yet, rename
.env.example
to.env.local
. Then add your connection string toMONGODB_URI
in.env.local
.
Run a local database for your dev setup so you can work offline and it's faster. You can read more here.
Mongoose (Optional)
Mongoose makes it easier to deal with MongoDB and has some cool features.
Models are defined in the folder /models
. Add any new models there.
The plugin toJSON is added to all models to remove the _id
and __v
(easier on front-end). Also if you add private: true
to any field it will be removed from the response. I.e. make email private so it's not sent to the front-end.
MongoServerSelectionError
Change the mongo.js
file to:
mongo.js
1import { MongoClient } from "mongodb";
2
3// This lib is use just to connect to the database in next-auth.
4// We don't use it anywhere else in the API routes—we use mongoose.js instead (to be able to use models)
5// See /libs/next-auth.js file.
6
7const uri = process.env.MONGODB_URI;
8const options = {};
9
10let client;
11
12if (!uri) {
13 console.group("⚠️ MONGODB_URI missing from .env");
14 console.error(
15 "It's not mandatory but a database is required for Magic Links."
16 );
17 console.error(
18 "If you don't need it, remove the code from /libs/next-auth.js (see connectMongo())"
19 );
20 console.groupEnd();
21} else if (process.env.NODE_ENV === "development") {
22 if (!global._mongoClient) {
23 global._mongoClient = new MongoClient(uri, options);
24 }
25 client = global._mongoClient;
26} else {
27 client = new MongoClient(uri, options);
28}
29export default client;
Supabase
Setup
- In Supabase SQL Editor, run this query to add a
profiles
table (an extension of the authenticated user to store data like Stripecustomer_id
, subscription access, etc...): - Go to the new
profiles
table and add 2 RLS policies: - Enable read access for authenticated users only
- Enable insert access for authenticated users only
- (Optional) If you want to collect leads with ButtonLead, create a new table called
leads
and add a RLS policy with insert access for anyone:
Supabase SQL Editor
1create table public.profiles (
2 id uuid not null references auth.users on delete cascade,
3 customer_id text,
4 price_id text,
5 has_access boolean,
6 email text,
7
8 primary key (id)
9);
10
11alter table public.profiles enable row level security;
Supabase SQL Editor
1create table public.leads (
2 id uuid default gen_random_uuid(),
3 email text,
4 created_at timestamp with time zone default timezone('utc'::text, now()) not null,
5
6 primary key (id)
7);
8
9alter table public.leads enable row level security;
Migrate to SSR (WIP)
- Delete the
/app/api/callback/route.js
API endpoint and replace it with the/app/api/auth/confirm/route.js
API endpoint.
/app/api/auth/confirm/route.js
1import { cookies } from "next/headers";
2import { NextResponse } from "next/server";
3
4import { createClient } from "@/libs/supabase-server";
5import config from "@/config";
6
7export async function GET(request) {
8 const { searchParams, origin } = new URL(request.url);
9
10 const code = searchParams.get("code");
11 const token_hash = searchParams.get("token_hash");
12 const type = searchParams.get("type");
13
14 try {
15 const cookieStore = cookies();
16 const supabase = createClient(cookieStore);
17
18 // For OAuth
19 if (code) {
20 const { error } = await supabase.auth.exchangeCodeForSession(code);
21
22 if (error) throw error;
23
24 return NextResponse.redirect(`${origin}${config.auth.callbackUrl}`);
25 }
26
27 // For Magic Link
28 if (token_hash && type) {
29 console.log("type & token_hash");
30
31 const { error } = await supabase.auth.verifyOtp({
32 type,
33 token_hash,
34 });
35
36 if (error) throw error;
37
38 return NextResponse.redirect(`${origin}${config.auth.callbackUrl}`);
39 }
40
41 throw new Error(
42 "Something went wrong while signing in! Please try again or contact support if the issue persists."
43 );
44 } catch (error) {
45 console.log(error);
46
47 // Redirect back to login page with error message
48 const redirectTo = request.nextUrl.clone();
49 redirectTo.pathname = config.auth.loginUrl;
50
51 redirectTo.searchParams.delete("code");
52 redirectTo.searchParams.delete("token_hash");
53 redirectTo.searchParams.delete("type");
54
55 redirectTo.searchParams.set("error", error.message);
56
57 return NextResponse.redirect(redirectTo);
58 }
59}