Files
supabase/apps/ui-library/content/docs/react/passwordless-auth.mdx
2026-01-15 16:22:58 -03:30

230 lines
6.7 KiB
Plaintext

---
title: Passwordless Authentication
description: Passwordless authentication block for React SPA with Magic Link and OTP support
---
<BlockPreview name="passwordless-auth-demo" />
## Installation
<BlockItem
name="passwordless-auth-react"
description="All needed components for passwordless authentication with Magic Link and OTP"
/>
## Folder structure
This block provides reusable components for passwordless authentication. Unlike framework-specific blocks, this doesn't include routing - you'll integrate these components into your own routing solution.
<RegistryBlock itemName="passwordless-auth-react" />
## Usage
Once you install the block in your React project, you'll get all the necessary components to set up passwordless email authentication with both Magic Link and OTP methods. You'll need to handle routing and navigation yourself.
### Getting started
After installing the block, you'll need to set up your Supabase client. Create a `.env` file with:
```env
VITE_SUPABASE_URL=
VITE_SUPABASE_PUBLISHABLE_OR_ANON_KEY=
```
- If you're using supabase.com, you can find these values in the [Connect modal](https://supabase.com/dashboard/project/_?showConnect=true&connectTab=frameworks&framework=nextjs) under App Frameworks or in your project's [API settings](https://supabase.com/dashboard/project/_/settings/api).
- If you're using a local instance of Supabase, you can find these values by running `supabase start` or `supabase status` (if you already have it running).
## Authentication Methods
This block supports two passwordless authentication methods:
### Magic Link
Magic Links are one-time use URLs sent to the user's email. When clicked, they automatically authenticate the user.
**When to use**: Simple, one-click authentication with minimal user interaction.
### OTP (One-Time Password)
OTPs are 6-digit codes sent to the user's email that they manually enter to authenticate.
**When to use**: When you need more control over the authentication flow or for mobile apps.
## Components
### PasswordlessLoginForm (Recommended)
A unified passwordless authentication form. Use the `method` prop to choose between Magic Link or OTP authentication.
```tsx
import { PasswordlessLoginForm } from '@/components/auth/passwordless-login-form'
export default function LoginPage() {
// Defaults to 'magic-link' if method prop is not provided
return <PasswordlessLoginForm method="magic-link" />
}
```
**Props:**
- `method?: 'magic-link' | 'otp'` - Authentication method (default: `'magic-link'`)
- `className?: string` - Additional CSS classes
**Examples:**
```tsx
// Magic Link authentication
<PasswordlessLoginForm method="magic-link" />
// OTP authentication
<PasswordlessLoginForm method="otp" />
```
### MagicLinkForm
Standalone Magic Link authentication form.
```tsx
import { MagicLinkForm } from '@/components/auth/magic-link-form'
export default function LoginPage() {
return <MagicLinkForm />
}
```
### OTPRequestForm & OTPVerifyForm
Two-step OTP authentication flow.
```tsx
// Request OTP
import { OTPRequestForm } from '@/components/auth/otp-request-form'
export default function RequestPage() {
return <OTPRequestForm />
}
// Verify OTP
import { OTPVerifyForm } from '@/components/auth/otp-verify-form'
export default function VerifyPage() {
return <OTPVerifyForm />
}
```
## Configuration
### Email Templates
You need to configure your email template based on which method you want to use:
#### For Magic Link (Default)
1. Go to [Email Templates](https://supabase.com/dashboard/project/_/auth/templates) in the Supabase Dashboard
2. Select "Magic Link" template
3. Use the following HTML:
```html
<h2>Magic Link</h2>
<p>Follow this link to login:</p>
<p>
<a href="{{ .SiteURL }}/auth/confirm?token_hash={{ .TokenHash }}&type=email"> Log In </a>
</p>
```
#### For OTP
1. Go to [Email Templates](https://supabase.com/dashboard/project/_/auth/templates) in the Supabase Dashboard
2. Select "Magic Link" template (yes, the same one)
3. Replace with the following HTML:
```html
<h2>One Time Login Code</h2>
<p>Please enter this code to sign in:</p>
<h1 style="font-size: 32px; letter-spacing: 4px;">{{ .Token }}</h1>
<p>This code will expire in 1 hour.</p>
```
<Callout type="info">
If you want to support both methods, you can include both the link and the token in your email template.
</Callout>
### Setting up Redirect URLs
1. Set the site URL in the [URL Configuration](https://supabase.com/dashboard/project/_/auth/url-configuration) settings in the Supabase Dashboard.
2. Add the following redirect URLs to your [URL Configuration](https://supabase.com/dashboard/project/_/auth/url-configuration):
- `http://localhost:3000/auth/confirm` (for development)
- `https://yourdomain.com/auth/confirm` (for production)
- `http://localhost:3000/protected` (or your authenticated route)
3. Update the redirect paths in the components to point to the logged-in routes in your app. Our examples use `/protected`, but you can set this to whatever fits your app.
### Configuration Options
#### Disable Auto Sign-Up
By default, users are automatically created if they don't exist. To prevent this:
```tsx
const { error } = await supabase.auth.signInWithOtp({
email,
options: {
shouldCreateUser: false, // Only allow existing users
},
})
```
#### OTP Expiration
Configure OTP expiration in the Supabase Dashboard:
1. Go to **Authentication** > **Providers** > **Email**
2. Find **Email OTP Expiration**
3. Set custom duration (default: 3600 seconds = 1 hour, max: 86400 seconds = 24 hours)
## Security
### Rate Limiting
By default, users can request a magic link or OTP once every 60 seconds to prevent abuse.
### Token Expiration
- Magic Links expire after 1 hour by default
- OTPs expire after 1 hour by default
## Troubleshooting
### Magic Link not working
- Verify redirect URLs are configured in Supabase Dashboard
- Check email template configuration
- Check browser console for errors, output them yourself if none are present
### OTP not received
- Verify email template shows `{{ .Token }}`
- Check spam folder
- Verify rate limiting hasn't been triggered (wait 60 seconds)
### "Invalid token" error
- Check if token has expired (default: 1 hour)
- Ensure user hasn't already used the token
- Verify system clock is synchronized
## Further reading
- [Passwordless email logins](https://supabase.com/docs/guides/auth/auth-email-passwordless)
- [Magic Link authentication](https://supabase.com/docs/guides/auth/auth-email-passwordless#with-magic-link)
- [OTP authentication](https://supabase.com/docs/guides/auth/auth-email-passwordless#with-otp)
- [Email templates](https://supabase.com/docs/guides/auth/auth-email-templates)
- [Authentication error codes](https://supabase.com/docs/guides/auth/debugging/error-codes)