Email Verification
Require users to confirm their email addresses before signing in.
Require users to confirm their email addresses before signing in.
Overview
Email verification adds a security layer by ensuring users own the email addresses they register with:
1. User signs up → Receives confirmation email
2. User clicks link → Email confirmed
3. User can now sign inUse cases:
- Prevent fake account creation
- Verify email ownership
- Enable password reset functionality
- Reduce spam and abuse
- Compliance requirements
Configuration
Enable Email Verification
{
"require_email_confirmation": true,
"email_confirmation_timeout": 86400
}Settings:
require_email_confirmation- Enable/disable (default: false)email_confirmation_timeout- Token expiry in seconds (default: 86400 = 24 hours)require_email_confirmation=truerequiresemail_enabled=true
Configure Email Sending
Email verification requires SMTP configuration:
{
"email_enabled": true,
"email_from_address": "noreply@myapp.com",
"email_from_name": "My App",
"smtp_host": "smtp.sendgrid.net",
"smtp_port": 587,
"smtp_username": "apikey",
"smtp_password": "SG.your-api-key",
"smtp_use_tls": true
}If require_email_confirmation is enabled, API updates that set email_enabled to false are rejected until require_email_confirmation is disabled first.
SMTP Providers:
- SendGrid: smtp.sendgrid.net:587
- AWS SES: email-smtp.{region}.amazonaws.com:587
- Mailgun: smtp.mailgun.org:587
- Gmail: smtp.gmail.com:587 (requires app password)
- Custom: Any SMTP server
Email Confirmation Flow
1. User Signs Up
POST /auth/signup
Authorization: Bearer <anon_key>
Content-Type: application/jsonRequest:
{
"email": "user@example.com",
"password": "password123"
}Response:
{
"access_token": "...",
"refresh_token": "...",
"user": {
"id": "uuid",
"email": "user@example.com",
"email_confirmed": false
}
}What happens:
- User created with
email_confirmed: false - Confirmation token generated and stored
- Confirmation email sent to user
2. Confirmation Email Sent
Email contains:
- Confirmation link with token
- Link expires after configured timeout
- Clear call-to-action button
Example link:
https://yourapp.com/confirm?token=abc123xyz7893. User Confirms Email
POST /auth/confirm
Authorization: Bearer <anon_key>
Content-Type: application/jsonRequest:
{
"token": "abc123xyz789"
}Response:
{
"message": "Email confirmed successfully"
}Also possible:
{
"message": "Email already confirmed"
}What happens:
- Token validated (project-scoped + expiration checked)
- User marked as
email_confirmed: true - Token cleared (one-time use)
4. User Can Sign In
POST /auth/signin
Authorization: Bearer <anon_key>Before confirmation:
{
"error": "email confirmation required - please check your email for confirmation link"
}After confirmation:
{
"access_token": "...",
"refresh_token": "...",
"user": {
"email_confirmed": true
}
}Resend Confirmation
If user didn't receive the email:
POST /auth/resend-confirmation
Authorization: Bearer <anon_key>
Content-Type: application/jsonRequest:
{
"email": "user@example.com"
}Response:
{
"message": "If the email exists and is unconfirmed, a confirmation link has been sent"
}Security:
- Generic response (doesn't reveal if email exists)
- Doesn't reveal if already confirmed
- If user exists and is unconfirmed, resend rotates token (old link becomes invalid)
- If user doesn't exist or is already confirmed, no email is sent
Frontend Integration
// Sign up
const { user, session } = await volcano.auth.signUp({
email: 'user@example.com',
password: 'password123'
});
if (!user.email_confirmed) {
showMessage('Please check your email for confirmation link');
}
// User clicks link from email → opens /confirm?token=abc123
// Confirm email
await volcano.auth.confirmEmail(urlParams.get('token'));
showMessage('Email confirmed! You can now sign in.');
// Sign in
const { user, session } = await volcano.auth.signIn({
email: 'user@example.com',
password: 'password123'
});
// ✓ Success - email is confirmed
// Resend confirmation (if needed)
await volcano.auth.resendConfirmation('user@example.com');
showMessage('Confirmation email resent');Email Customization
Custom Subject Lines
{
"email_confirmation_subject": "Welcome! Confirm your email",
"email_password_reset_subject": "Reset your password for MyApp",
"email_password_changed_subject": "Security alert: Password changed"
}Custom Email Templates
Create custom templates per project (optional - overrides defaults):
POST /projects/{projectId}/email-templates
Authorization: Bearer <platform_token>
Content-Type: application/jsonRequest:
{
"template_type": "confirmation",
"subject": "Welcome to MyApp!",
"html_body": "...",
"text_body": "..."
}Template variables:
{{.Email}}- User's email address{{.ConfirmationURL}}- Confirmation link with token{{.ProjectName}}- Your project name{{.AppName}}- Your app name
Security
Token Security
Cryptographically secure:
- Generated using crypto/rand
- 64 characters (32 bytes hex-encoded)
- One-time use (cleared after confirmation)
- Time-limited expiration
Project-scoped:
- Tokens only work within their project
- Cannot use Project A token in Project B
Email Enumeration Prevention
All responses are generic:
- Resend confirmation: Same message whether email exists or not
- Already confirmed: Same message as not found
- Prevents attackers from discovering registered emails
Rate Limiting
Signup is rate limited per project and client IP, which also caps the confirmation emails it sends. See Rate limiting.
Configuration Examples
SendGrid
curl -X PUT https://api.volcano.dev/projects/PROJECT_ID/auth/config \
-H "Authorization: Bearer TOKEN" \
-d '{
"email_enabled": true,
"email_from_address": "noreply@myapp.com",
"email_from_name": "My App",
"smtp_host": "smtp.sendgrid.net",
"smtp_port": 587,
"smtp_username": "apikey",
"smtp_password": "SG.your-sendgrid-api-key",
"smtp_use_tls": true,
"require_email_confirmation": true
}'AWS SES
curl -X PUT https://api.volcano.dev/projects/PROJECT_ID/auth/config \
-H "Authorization: Bearer TOKEN" \
-d '{
"email_enabled": true,
"email_from_address": "noreply@myapp.com",
"smtp_host": "email-smtp.us-east-1.amazonaws.com",
"smtp_port": 587,
"smtp_username": "AKIAIOSFODNN7EXAMPLE",
"smtp_password": "your-smtp-password",
"smtp_use_tls": true,
"require_email_confirmation": true
}'Mailgun
curl -X PUT https://api.volcano.dev/projects/PROJECT_ID/auth/config \
-d '{
"email_enabled": true,
"email_from_address": "noreply@mg.myapp.com",
"smtp_host": "smtp.mailgun.org",
"smtp_port": 587,
"smtp_username": "postmaster@mg.myapp.com",
"smtp_password": "your-mailgun-smtp-password",
"smtp_use_tls": true,
"require_email_confirmation": true
}'Behavior
When Email Verification Enabled
Signup:
- User created with
email_confirmed: false - Confirmation email sent automatically
- Returns access token (can use app but can't sign in again)
Signin:
- Blocked if email not confirmed
- Error: "email confirmation required"
- User must confirm email first
Resend:
- Generates new token
- Sends new email
- Previous token becomes invalid
When Email Verification Disabled
Signup:
- User created with
email_confirmed: false(or true, doesn't matter) - No confirmation email sent
- Can sign in immediately
Signin:
- Works regardless of email_confirmed status
- No blocking
Token Expiration
Default: 24 hours (86400 seconds)
Configurable:
{"email_confirmation_timeout": 3600} // 1 hour
{"email_confirmation_timeout": 604800} // 7 daysAfter expiration:
- Token becomes invalid
- User must request new confirmation email
- Use resend-confirmation endpoint
Troubleshooting
Emails Not Sending
Check configuration:
# Get current config
curl https://api.volcano.dev/projects/PROJECT_ID/auth/config \
-H "Authorization: Bearer TOKEN"
# Verify:
# - email_enabled: true
# - smtp_host, smtp_port set correctly
# - smtp_username, smtp_password are correct
# - email_from_address is validTest SMTP connection:
- Use
telnet smtp.host.com 587to verify connectivity - Check SMTP credentials with provider
- Verify from address is authorized (SPF/DKIM)
Emails Going to Spam
Improve deliverability:
- Set up SPF records for your domain
- Configure DKIM signing
- Use verified sender address
- Keep email content simple (default templates optimized)
- Monitor bounce rates
User Can't Find Email
Common issues:
- Email in spam folder
- Wrong email address entered
- Email service delay
- Token expired (user waited too long)
Solution:
- Use resend-confirmation endpoint
- Check spam folder
- Verify email address is correct
See Also
Configuring Authentication Methods Per Project
Control which authentication methods each project enables — email/password, OAuth providers, and anonymous — to match your use case.
Managed Hosted Auth Pages
Managed hosted auth pages let you serve customizable authentication pages directly from Volcano for each project.