NextAuth Magic Link: Code Examples for Success

published on 06 December 2023

Most developers would likely agree:

Implementing seamless passwordless authentication can be an arduous endeavor.

However, with NextAuth's magic link feature, you can easily incorporate passwordless sign-in into your application, providing users a frictionless login experience that drives higher conversion.

In this code-centric guide, you'll discover step-by-step techniques for configuring, customizing, and troubleshooting NextAuth magic links, equipping you to embrace true passwordless functionality.

NextAuth's magic link feature offers a passwordless authentication solution that creates a smooth onboarding experience for users. By removing the friction of memorable passwords, magic links provide a convenient way to securely sign in.

The Allure of Magic Links: NextAuth's Passwordless Gateway

Magic links allow users to sign in instantly using a login link sent to their email or phone. This enhances usability and conversions by:

  • Eliminating password fatigue - users don't need to create or remember complex passwords. Just click the login link.
  • Providing better security - magic links are single-use and expire quickly, reducing vulnerabilities.
  • Creating a streamlined flow - users can sign up and sign in easily with no password barriers.

By implementing NextAuth's magic link handler, developers can tap into these benefits with just a few lines of code.

NextAuth's Magic Touch: Seamless User Sessions

Once users click the login link, NextAuth handles the session authentication seamlessly.

Here is a code snippet showing how useSession() and signIn() simplify the integration:

import { useSession, signIn } from "next-auth/react"

function Component() {
  const { data: session } = useSession()

  const handleLogin = () => {
    signIn() 
  }
  
  // ...
}

With this approach, authentication state and logic is abstracted away. No need to manually deal with tokens or sessions.

NextAuth Magic Link: The Key to Higher Conversion Rates

By removing login friction, NextAuth's magic links enable:

  • Faster signups - users can easily create accounts and access content faster.
  • Less abandoned carts - signed-in users are more likely to complete purchases.
  • Better analytics - gain insights on site engagement with authenticated users.

Ultimately, magic links deliver convenience that converts visitors into customers. Integrating them into your Next.js app is simple with NextAuth.

Outlining the steps to set up magic link authentication in a Next.js application with NextAuth.

Starting Your NextAuth Journey: Installation and Setup

Guiding through the initial steps of integrating the NextAuth library into your project.

To get started with NextAuth magic link in your Next.js project, first install the NextAuth package:

npm install next-auth

or

yarn add next-auth

Next, create an /pages/api/auth/[...nextauth].js file and initialize a NextAuth handler:

import NextAuth from "next-auth";
import Providers from "next-auth/providers";

export default NextAuth({
  // Configure providers here
  providers: [
    Providers.Email({
      server: {
        host: "",
        port: "",
        auth: {
          user: "",
          pass: ""
        }
      },
      from: "" 
    })
  ] 
});

This sets up the authentication foundations. We'll build on this handler further in later sections.

Crafting Your Authentication Strategy: NextAuth Session Configuration

Detailing the customization options for sessions and how they impact the magic link flow.

A key part of configuring NextAuth magic link is appropriately setting up session behavior. This determines how long the magic link is valid for, whether users stay logged in after validating the link, and more.

Some key options to configure sessions include:

session: {
  // Use JSON Web Tokens for session instead of database sessions
  // This option can be used with or without a database for users/accounts
  jwt: true,  

  // Seconds - How long until an idle session expires and is no longer valid.
  maxAge: 30 * 24 * 60 * 60, // 30 days
  
  // Seconds - Throttle how frequently to write to database to extend a session.
  // Use it to limit write operations. Set to 0 to always update the database.
  updateAge: 24 * 60 * 60 // 24 hours
}

The jwt flag is highly recommended for magic link to keep session data decentralized.

Modifying maxAge adjusts how long the magic link login is valid for. Lower values make sessions expire faster.

updateAge throttles how often idle sessions get refreshed. Higher values reduce database load.

Linking Up with Email: Integrating Gmail and Other Providers

Instructions on connecting NextAuth with email providers like Gmail, SendGrid, and Postmark for dispatching magic links.

To send magic links, NextAuth requires configuring an email provider. Popular options include:

Gmail

Providers.Email({
  server: {
    host: "smtp.gmail.com",
    port: 587,
    auth: {
      user: "myaccount@gmail.com",
      pass: "apppassword" 
    }
  },
  from: "myaccount@gmail.com"
})

SendGrid

Providers.Email({
  server: {
    host: "smtp.sendgrid.net",
    port: 587,
    auth: {
      user: "apikey",
      pass: "SG.xxxxxxxx.xxxx"
    }
  },
  from: "myaccount@sendgrid.com"
})

Postmark

Providers.Email({
  server: {
    host: "smtp.postmarkapp.com",
    port: 25,
    auth: {
        user: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
        pass: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
    }
  },
  from: "myaccount@mydomain.com" 
})

The credentials can be obtained from the respective provider dashboards.

A walkthrough of how to generate and dispatch a magic link using NextAuth.

With an email provider configured, generating and sending a magic link is straightforward:

API Route

// pages/api/auth/[...nextauth].js

export default NextAuth({
  providers: [
    // ...email provider
  ],
  callbacks: {
    async signIn({ user, account, profile, email, credentials }) {
      if (account.provider === "email") {
        // Generate magic link for email logins
        return true;
      }
      return false
    } 
  }
})

Frontend code

// Generate magic link 
const res = await fetch("/api/auth/signin/email", {
  method: "POST",
  body: JSON.stringify({ email: "user@domain.com" }),
  headers: { "Content-Type": "application/json" }
});

This will dispatch a magic link email to the user. When validated, it will log them into your app!

The login flow can be further customized via NextAuth callbacks.

Tips for personalizing the magic link email template to align with your brand and user experience.

NextAuth uses a default minimal template for its magic link emails. To make it match your product better, you can tweak the template -

Custom Template

// pages/api/auth/[...nextauth].js

callbacks: {
  async signIn({ user, account, profile, email, credentials }) {
    // Send custom magic link email template
    return await sendVerificationRequest({
      identifier: email,
      url: process.env.NEXTAUTH_URL,
      provider: { id: "email", name: "Email" },
      template: 'path/to/template.html', // Or pass template string    
      theme: {
        // Customize colors, brand name, etc  
      }
    });
  }
}  

The template file can override any default text, include new info like images and branding, and even pass dynamic params for personalization.

As your users grow accustomed to your email style guide, consider making your magic links fit right in!

sbb-itb-5683811

Embracing Complete Passwordless Authentication

How to transition to a fully passwordless authentication system using NextAuth's magic link feature.

Eliminating Passwords: Configuring Next-auth Passwordless Entry

NextAuth's magic link feature enables completely passwordless authentication flows. By removing password fields from the sign-in and sign-up forms, we can provide a frictionless experience for users.

Here is an example of how to configure NextAuth for passwordless email magic links:

import NextAuth from "next-auth"
import EmailProvider from "next-auth/providers/email"

export default NextAuth({
  providers: [
    EmailProvider({
      server: {
        host: process.env.EMAIL_SERVER_HOST,
        port: process.env.EMAIL_SERVER_PORT,
        auth: {
          user: process.env.EMAIL_SERVER_USER,
          pass: process.env.EMAIL_SERVER_PASSWORD  
        }
      },
      from: process.env.EMAIL_FROM,
    }),
  ],
  callbacks: {
    session: async (session, user) => {  
      session.user.id = user.id  
      return Promise.resolve(session)
    }
  },
  pages: {
    signIn: "/auth/signin",
  } 
})

This configures NextAuth to use the EmailProvider for passwordless sign-in. We specify the email server details and handle the session in the callbacks. The pages.signIn sets the sign-in page route.

With this set up, users will receive a magic link via email to sign in rather than entering a password. This simplifies the authentication flow considerably.

Ensuring User Authenticity: Email Verification with Next-auth

To validate new user accounts created via magic link sign-up, we can add email verification with NextAuth.

Below is an example using SendGrid as the email delivery service:

import NextAuth from "next-auth"
import Providers from "next-auth/providers"
import Adapters from "next-auth/adapters"
import nodemailer from "nodemailer"

const sendgridTransport = nodemailer.createTransport({
  service: "SendGrid",
  auth: {
    user: process.env.SENDGRID_USER,
    pass: process.env.SENDGRID_PASSWORD
  }
});

export default NextAuth({
  providers: [
    Providers.Email({
      server: process.env.EMAIL_SERVER,
      from: process.env.EMAIL_FROM,
    })
  ],
  adapter: Adapters.TypeORM.Adapter(), 
  callbacks: {
    session: async (session, user) => {
      session.user.id = user.id;  
      return Promise.resolve(session);
    }
  },
  events: {
    verifySignup: async (message) => {    
      await transporter.sendMail({
        ...message,
        to: message.user.email, 
      });
    }
  },
  pages: {
    signIn: "/auth/signin",
  }
});

The verifySignup event handler sends a verification email to new users with a confirmation link. Once confirmed, the email will be marked as verified.

This adds an extra validity check before allowing full access. NextAuth can also resend verification emails if needed.

Fortifying Security: Adding Next-auth OTP for Two-Factor Authentication

For additional security, we can implement 2FA using OTP codes with NextAuth.

Below generates OTP secrets during sign-up:

import { authenticator } from "otplib";

// Inside signup callback
let otpauth = authenticator.generateSecret(); 

// Save otpauth against new user
insertNewUser({
  email: profile.email,
  otpauth: otpauth  
});

// Send OTP QR code email
sendOTPQREmail(profile.email, otpauth);

Then when signing in, we can prompt for the OTP code:

// Verify OTP on signin

import { authenticator } from "otplib";

let verified = authenticator.check(otp, otpauth); 

if(!verified) {
  return res.status(401).json({ message: "Invalid OTP" });
} else {
  // Continue signin flow
}

This verifies the OTP before allowing sign-in. The user scans the OTP QR code to connect an authenticator app for code generation.

Adding an extra authentication factor boosts account security significantly.

Refining User Experience for Authentication Failures

If authentication fails for some reason, we should handle it gracefully:

// pages/auth/signin.js

import { useSession } from "next-auth/react"

export default function SignIn() {
  
  const { status } = useSession();

  // Display error message 
  if (status === "verificationError") {
    return (
      <Message type="error">
        <p>Failed to authenticate magic link.</p>
        <Button onClick={() => signIn()}>
          Resend magic link
        </Button>
      </Message>
    );
  }

  return <AuthForm />
}

This provides user feedback on a sign-in error, with the option to retry.

For other failures, we can implement:

  • Refresh token errors - Re-authenticate user
  • Expired tokens - Trigger signOut()
  • Email delivery issues - Request email verification resend

Proper error handling ensures a smooth authentication experience.

Mastering Advanced Configurations and Customizations

Diving deeper into advanced customization options for optimizing the magic link experience in NextAuth.

Managing User Presence: NextAuth Session Lifespan Customizations

The session property in NextAuth.js allows controlling session duration and expiration policies.

Here is an example to set session length to 1 hour:

session: {
  maxAge: 60 * 60 
}

Additional options include:

  • updateAge: Sets how often session is updated in seconds
  • absoluteSessionTimeout: Session expires after this time period regardless of activity

This allows adapting session length and timeouts to suit application needs. Shorter durations increase security, while longer ones improve user experience by reducing repeated logins.

NextAuth.js supports adding OAuth providers alongside email magic link. This allows users to sign in through social accounts or email magic link.

providers: [
  OAuthProvider({
    clientId: process.env.GITHUB_ID,
    clientSecret: process.env.GITHUB_SECRET
  }),
  EmailProvider({
    server: {
      host: process.env.SMTP_HOST,
      ...
    },
    from: process.env.EMAIL_FROM
  }),
]  

Benefits include wider sign-in options for users and ability to migrate existing social login users to magic link.

Magic link generation can be handled by a serverless function instead of API route. This simplifies integration and avoids running extra services.

Here is an example using Vercel serverless functions:

export default async (req, res) => {
  await NextAuth.handleVerificationRequest({
    token: req.body.token,
    secret: process.env.NEXTAUTH_SECRET,
    provider: EmailProvider({ ... })
  })
  res.end()
}

This delegates authentication to Vercel functions while keeping application code clean.

Keeping Track: Monitoring NextAuth Sign-in Events

NextAuth.js provides callbacks to track sign-in events for analytics:

callbacks: {
  signIn: async (user, account, profile) => { 
    console.log('user logged in', user)
  }  
}

Usage includes:

  • Tracking login frequency
  • Analyzing auth errors
  • Maintaining user logs

This data offers valuable usage insights to improve authentication flows.

Troubleshooting NextAuth Magic Links: Common Pitfalls and Solutions

Issues like expired links or delivery failures can frustrate users. Solutions include:

  • Use queue system to retry failed requests
  • Adjust link expiration times
  • Inform users of email delays

Additionally, check server logs for clues on failure causes. Proactively addressing problems enhances reliability and prevents login issues.

Your Magical Journey: Recap and Future Exploration

Summarizing the essential knowledge acquired about NextAuth magic link and suggesting paths for further learning and experimentation.

NextAuth's magic link support provides a passwordless authentication flow for signing in users. Here is a recap of some key learnings:

  • Magic links enhance user experience by removing the need to remember passwords. Users simply click the login link sent to their email.
  • Setup requires adding the EmailProvider to NextAuth and enabling the email magic link feature. For example:
providers: [
  Providers.Email({
    server: process.env.EMAIL_SERVER,
    from: process.env.EMAIL_FROM,
    sendVerificationRequest: {
      magicLink: true,
    },
  }),
]
  • Magic links can be customized via the callbacks.magicLink callback. This allows modifying the URL, link lifespan, and redirect behavior.
  • Additional providers like GitHub can be chained to enable magic link sign in with a fallback to OAuth.

While magic links simplify login flows, use cases requiring high security may need additional factors like 2FA. But for most apps, passwordless magic links provide convenience without compromising safety.

Extending Your NextAuth Mastery: Additional Resources

To continue advancing your NextAuth skills, here are helpful learning materials:

With these resources, developers can gain extensive hands-on experience building secure, scalable, production-ready login flows with NextAuth.

The Final Spell: Concluding Thoughts on Passwordless Evolution

In conclusion, NextAuth magic links represent the next evolution in authentication UX. Removing cumbersome password entry on mobile keyboards delivers a magical login experience. As more businesses adopt passwordless, users can expect smooth single tap sign-ins across their apps. While tradeoffs exist, the simplicity of magic links makes passwordless a strong contender for the future of digital identity. NextAuth brings this future closer for developers seeking to create truly magical web experiences.

Related posts

Read more

Make your website with
Unicorn Platform Badge icon