Authentication
NextAuth.js v5 with OAuth providers (Google, GitHub) and passwordless magic links. All auth routes and protected pages are pre-configured.
How it works
- User visits
/login - Chooses OAuth provider or enters email for magic link
- After verification, redirected to
/app/dashboard - Session stored in database with secure HTTP-only cookies
Key files
lib/auth.ts- NextAuth configurationlib/auth/helpers.ts-requireUser(),getCurrentUser()lib/auth/magic-link.ts- Token generation, hashing, verificationapp/login/page.tsx- Sign-in pageapp/api/auth/[...nextauth]/route.ts- NextAuth API routeapp/api/auth/magic-link/request/route.ts- Magic link request endpointapp/auth/magic-link/verify/route.ts- Magic link verificationcomponents/magic-link-form.tsx- Email input formemails/MagicLinkSignInEmail.tsx- Magic link email template
Environment variables
AUTH_SECRET=<openssl rand -base64 32>
# OAuth (optional if using magic links only)
AUTH_GOOGLE_ID=xxx.apps.googleusercontent.com
AUTH_GOOGLE_SECRET=GOCSPX-xxx
AUTH_GITHUB_ID=Iv1.xxx
AUTH_GITHUB_SECRET=xxx
# Magic link settings (optional, have defaults)
AUTH_MAGIC_LINK_TOKEN_TTL_MINUTES=15
AUTH_MAGIC_LINK_RATE_LIMIT_PER_HOUR=5
Protecting pages
All pages under app/app/ are automatically protected. The layout calls requireUser().
app/app/projects/page.tsx
// app/app/projects/page.tsx
import { requireUser } from "@/lib/auth/helpers";
export default async function ProjectsPage() {
const user = await requireUser();
return <div>Welcome, {user.email}</div>;
}
Magic link security
- Tokens are 32 bytes of cryptographic randomness
- Only SHA-256 hashes stored in database
- Single-use and time-limited (15 min default)
- Rate limited: 5 requests/hour per email and IP
- No user enumeration (always returns success)
Adding a new OAuth provider
- Add credentials to
lib/auth.tsproviders array - Add environment variables
- Update login page UI if needed
Related: Email for customizing magic link emails