Details below are from the Auth.js documentation on 17 October 2026. Check it for current details.
How Auth.js email sign-in works
- The user enters their address on your sign-in page.
- Auth.js stores a verification token in your database (a database adapter is required) and emails a magic link through your email provider.
- Opening the link within 24 hours signs the user in, and uses the token up.
Why the email doesn’t arrive
Auth.js hands the email to your provider, so its rules apply. Providers in sandbox or test mode only send to verified addresses: Resend without a verified domain, Amazon SES before production access, Mailgun sandbox domains, Postmark before approval. A test inbox can’t receive their mail until that’s sorted. Test email not arriving? covers each one.
Also check the link’s host: Auth.js builds it from your site’s URL setting (AUTH_URL, or NEXTAUTH_URL in older versions), so a leftover localhost value sends people there. See why emails link to localhost.
Test it by hand
- Create an address in Proxy Mail QA.
- Request a sign-in link with it on your app.
- The link appears on the address’s row within seconds, marked as a sign-in link. Open it, then try it again: it should no longer work.
Automate it
import { test, expect } from 'proxymail-qa/playwright';
test('email sign-in works once', async ({ page, qa }) => {
const { address } = await qa.createAddress();
const requested = new Date();
await page.goto('/api/auth/signin');
await page.getByLabel('Email').fill(address);
await page.getByRole('button', { name: 'Sign in with Email' }).click();
const { value: link } = await qa.waitForLink(address, { type: 'magic_signin', since: requested });
await page.goto(link);
await expect(page).toHaveURL(/\/$/);
});
Match the page and labels to your sign-in form. More in Test sign-up emails in Playwright and magic-link testing.