Auth.js / NextAuth email with Groundmail

Auth.js (NextAuth) magic-link sign-in needs an email provider and a database adapter (tokens are stored in the DB).

Groundmail ships a drop-in provider: Groundmail from groundmail-authjs (also groundmail/authjs).


Prerequisites

  1. Groundmail account + gm_… API key
  2. Verified sending domain (or Sandbox for self-tests — see Quickstart)
  3. Auth.js app with a database adapter
npm install groundmail-authjs groundmail next-auth
AUTH_GROUNDMAIL_KEY=gm_your_key_here
# or: GROUNDMAIL_API_KEY=gm_your_key_here

Setup

// auth.ts
import NextAuth from 'next-auth'
import Groundmail from 'groundmail-authjs'
// import your adapter, e.g. Prisma / Drizzle / …

export const { handlers, auth, signIn, signOut } = NextAuth({
  adapter: /* … */,
  providers: [
    Groundmail({
      from: 'noreply@yourdomain.com',
    }),
  ],
})

Users sign in at /api/auth/signin with email. Groundmail delivers the magic link (auth=authjs-magic-link tag).


Options

Option Default Purpose
from sandbox-style placeholder Verified sender (set this for production)
apiKey AUTH_GROUNDMAIL_KEY or GROUNDMAIL_API_KEY API key
baseUrl https://api.groundmail.dev API base URL
maxAge 86400 (24h) Token lifetime (seconds)
sendVerificationRequest built-in Custom email body / send logic
client — Inject a Groundmail instance (tests)

Customize the email

Pass your own sendVerificationRequest (Auth.js pattern):

Groundmail({
  from: 'noreply@yourdomain.com',
  async sendVerificationRequest({ identifier, url, provider }) {
    const { Groundmail: Client } = await import('groundmail')
    const tx = new Client(process.env.GROUNDMAIL_API_KEY!)
    await tx.emails.send({
      from: provider.from,
      to: identifier,
      subject: 'Your sign-in link',
      html: `<p><a href="${url}">Sign in</a></p>`,
      text: `Sign in: ${url}`,
    })
  },
})

Or send with React Email from that callback.