DEV Community

ivanleomk
ivanleomk

Posted on

Magic Link Sign in using Next Auth, Prisma, Amazon SES and Supabase

Introduction

I've always been curious about how the magic links that all websites are using nowadays work and over the weekend, after watching a few videos, I put together a quick prototype that manages to do so. Let me walk you through it!

Installing Necessary Libraries and bootstrapping the project

Before we begin, we need to start by bootstrapping a new NextJS App. You can do so by running the command



npx create-next-app --ts


Enter fullscreen mode Exit fullscreen mode

This will help us to boot upa NextJS App with Typescript auto configured. Now we need to install our dependencies, which will be prisma and next-auth. We can do so by running the commands



yarn add prisma next-auth @next-auth/prisma-adapter nodemailer


Enter fullscreen mode Exit fullscreen mode

Let's also add a .env file which looks like what we have below



DATABASE_URL = 
SMTP_HOST= 
SMTP_PORT = 587 
SMTP_USER = 
SMTP_PASSWORD = 
SMTP_FROM=
NEXTAUTH_SECRET = 


Enter fullscreen mode Exit fullscreen mode

Supabase

Creating Our Project

We now need to create a quick database with Supabase. If you don't have an account, you can sign up here and create a free account. Once you've done so, simply go over to the dashboard and create a new project.

Screenshot 2022-08-09 at 2 25 36 PM

Make sure to write down your password so that you don't forget it. You'll need it to connect to your database later on.

Grabbing our Database URI

We can find our database URI by navigating to settings -> database -> connection string -> URI. I've provided some snapshots below to help you find it in your project.

Screenshot 2022-08-09 at 3 24 08 PM
Screenshot 2022-08-09 at 3 24 24 PM
Screenshot 2022-08-09 at 3 25 52 PM

The password will simply be the password that you set up when configuring the project.

Prisma

Configuring our schema

Make sure that you've updated the .env file with the database URI that we grabbed from supabase. This should be named DATABASE_URL in the .env file.

Now that we've got a working database, we can start to setup our prisma schema to work nicely with it. Let's start by running the command



npx prisma init


Enter fullscreen mode Exit fullscreen mode

This will create for us a new schema.prisma file which we want to override with the code below



generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

model Account {
  id                String  @id @default(cuid())
  userId            String
  type              String
  provider          String
  providerAccountId String
  refresh_token     String? @db.Text
  access_token      String? @db.Text
  expires_at        Int?
  token_type        String?
  scope             String?
  id_token          String? @db.Text
  session_state     String?

  user User @relation(fields: [userId], references: [id], onDelete: Cascade)

  @@unique([provider, providerAccountId])
}

model Session {
  id           String   @id @default(cuid())
  sessionToken String   @unique
  userId       String
  expires      DateTime
  user         User     @relation(fields: [userId], references: [id], onDelete: Cascade)
}

model User {
  id            String    @id @default(cuid())
  name          String?
  email         String?   @unique
  emailVerified DateTime?
  image         String?
  accounts      Account[]
  sessions      Session[]
}

model VerificationToken {
  identifier String
  token      String   @unique
  expires    DateTime

  @@unique([identifier, token])
}


Enter fullscreen mode Exit fullscreen mode

Let's now test that our database is working as we planned by running a migration using the command



npx prisma migrate dev


Enter fullscreen mode Exit fullscreen mode

This will apply our changes to our database and we can verify this by going back to supabase and verifying that our new tables have been created as we wanted.

Screenshot 2022-08-09 at 3 32 09 PM

Configuring Amazon Simple Email Service ( SES )

Creating a Verified Identity

Amazon SES is a email service provided by Amazon which helps you to send emails using either the AWS SDK or an SMTP Endpoint they provide. For This article, we will be using their SMTP credentials.

First, create an AWS account if you haven't. AWS is Amazon's cloud computing wing which provides a variety of different services. You can do so here. Once you've created a new account, navigate to the SES dashboard and click on Verified Identities.

Screenshot 2022-08-09 at 3 15 48 PM

Screenshot 2022-08-09 at 3 16 21 PM

If you own a domain, you'll need to wait a while before being able to start sending emails out with your registered domain.

Creating an IAM User with SMTP credentials

Now that we've got ourselves a working verified domain, we now need to configure a valid IAM user with SMTP credentials. In order to do so, we can simply navigate to the Account Dashboard screen in the SES page

Screenshot 2022-08-09 at 3 19 02 PM

Now simply create a new user with the wizard. Name it anything you like but note down the username and password that Amazon provides you with. You'll need it to configure our NextAuth Login Flow.

With this, we've got ourselves all the credentails we need.

NextAuth

Configuring our Provider

Let's now start to set up our NextAuth in our project. Let's first open our _app.tsxfile and add in the NextAuth Providers



import "../styles/globals.css";
import { SessionProvider } from "next-auth/react";

export default function App({
  //@ts-ignore
  Component,
  //@ts-ignore
  pageProps: { session, ...pageProps },
}) {
  return (
    <SessionProvider session={session}>
      <Component {...pageProps} />
    </SessionProvider>
  );
}


Enter fullscreen mode Exit fullscreen mode

As you can seem we now have a new Session Provider which can help us to utilise NextAuth in our application. This helps track the individual sessions which are running in our app and in turn utilise useful functionality such as the useSession hook in our app.

Updating Next Auth API Route

We now need to create a new route in the NextJS Project that we have created. This will have the route of pages/api/auth/[...nextauth].js and will look like what we have below.



import NextAuth from "next-auth";
import EmailProvider from "next-auth/providers/email";
import { PrismaAdapter } from "@next-auth/prisma-adapter";
import { PrismaClient } from "@prisma/client";

const prisma = new PrismaClient();

export default NextAuth({
  // Configure one or more authentication providers
  providers: [
    EmailProvider({
      server: `smtp://${process.env.SMTP_USER}:${process.env.SMTP_PASSWORD}@${process.env.SMTP_HOST}:${process.env.SMTP_PORT}`,
      from: process.env.SMTP_FROM,
    }),
    // ...add more providers here
  ],
  adapter: PrismaAdapter(prisma),
});



Enter fullscreen mode Exit fullscreen mode

We now need to make sure that our .env file has the relevant values

  • SMTP_USER : This is the username generated by AWS when you created your new IAM user
  • SMTP_PASSWORD: This is the password generated by AWS when we created the new IAM user with SMTP priviledges.
  • SMTP_HOST: This will depend on what region you want to send the emails in. For mine it is email-smtp.ap-southeast-1.amazonaws.com and you can find the specific SMTP endpoint to use here
  • SMTP_PORT: 587
  • SMTP_FROM: This is the value that will appear in the FROM field in your email. Note that you can only add enails that have been verified by SES in this step.

Configuring index.tsx

We've now got everything set up. Let's test to see if it's working, to do so, we can use our NextJS application to test. Let's scaffold a quick application which uses the useSession hook in order to see if our magic link authentication works



import type { NextPage } from "next";
import { signIn, signOut, useSession } from "next-auth/react";

const Home: NextPage = () => {
  const { data: session } = useSession();

  if (session) {
    return (
      <div>
        Authenticated <button onClick={() => signOut()}>Sign Out</button>
      </div>
    );
  }

  return (
    <div>
      Unauthenticated Boi <button onClick={() => signIn()}>Sign in</button>
    </div>
  );
};

export default Home;


Enter fullscreen mode Exit fullscreen mode

We can then try to sign in by clicking the button Sign In

Screenshot 2022-08-09 at 3 43 11 PM

This brings us to the sign in page as seen below

Screenshot 2022-08-09 at 3 43 40 PM

Which when we fill in our email redirects us to

Screenshot 2022-08-09 at 3 44 18 PM

We can verify that our email function works by checking whether we have recieved an email. In this case, I've used a domain admin@ivanleo.com.

Screenshot 2022-08-09 at 3 42 25 PM

Which when we click then allows our user to login and display the Authenticated screen as seen below.

Screenshot 2022-08-09 at 3 45 38 PM

Deploying on Vercel

Let's deploy this new project that we've put together. We can do so by using Vercel, which provides a simple One-Click deployment from Github. Simply navigate over and select the project from the New Project tab. You'll then want to just enable the default settings as seen below.

Screenshot 2022-08-09 at 3 49 20 PM

Once everything is built, you'll need to add in every single environment variable which you configured in your .env file to your vercel project. You can do so at Settings -> Enviroment Variables.. Now just trigger a redeployment of your project and you should be good to go!

Top comments (0)