← All components

Supabase Auth Pages (Login + Callback)

Adds a /login page (email magic link) styled with shadcn/ui Button, and the /auth/callback route handler that exchanges the OAuth/magic-link code for a session.

Copy the files below, or open this folder on GitHub. Each file is stamped with a limited-use licence, generator and date. SHA-256 is of the published catalog bytes, before the stamp.

id
supabase-auth-ui
stack
Next.js
version
1.1.0
compatibility
nextjs >=16 <17 · react >=19 <20
requires
supabase-client, shadcn-ui
env vars
Verified passing · daily buildIntegrity sha256:e7fe10fcd959a1e4

Files (2)

app/login/page.tsx · sha256:e7fe10fcd959a1e4…
// Licensed by BotKelp — https://www.botkelp.com

'use client';

import { useState, type FormEvent } from 'react';
import { useSupabase } from '@/components/supabase-provider';
import { Button } from '@/components/ui/button';

export default function LoginPage() {
  const supabase = useSupabase();
  const [email, setEmail] = useState('');
  const [status, setStatus] = useState<'idle' | 'sending' | 'sent' | 'error'>('idle');

  async function handleSubmit(event: FormEvent<HTMLFormElement>) {
    event.preventDefault();
    setStatus('sending');
    const { error } = await supabase.auth.signInWithOtp({
      email,
      options: { emailRedirectTo: `${window.location.origin}/auth/callback` },
    });
    setStatus(error ? 'error' : 'sent');
  }

  return (
    <main className="mx-auto flex min-h-screen max-w-sm flex-col justify-center gap-4 p-6">
      <h1 className="text-2xl font-semibold">Sign in</h1>
      <form onSubmit={handleSubmit} className="flex flex-col gap-3">
        <input
          type="email"
          required
          value={email}
          onChange={(event) => setEmail(event.target.value)}
          placeholder="you@example.com"
          className="rounded-md border border-slate-200 px-3 py-2"
        />
        <Button type="submit" disabled={status === 'sending'}>
          {status === 'sending' ? 'Sending link…' : 'Send magic link'}
        </Button>
      </form>
      {status === 'sent' && <p className="text-sm text-slate-600">Check your email for a login link.</p>}
      {status === 'error' && <p className="text-sm text-red-600">Something went wrong. Try again.</p>}
    </main>
  );
}