Deploy your authentication system to production
This guide covers deploying applications using @warpy-auth-sdk/core to popular hosting platforms with production-ready configurations.
AUTH_SECRET (32+ characters)Vercel is the recommended platform for Next.js applications.
npm install -g vercel
# or use npx
npx vercelSet environment variables in Vercel dashboard or CLI:
# Via CLI
vercel env add AUTH_SECRET production
vercel env add GOOGLE_CLIENT_ID production
vercel env add GOOGLE_CLIENT_SECRET production
vercel env add GOOGLE_REDIRECT_URI production
vercel env add DATABASE_URL production
# Or via dashboard: https://vercel.com/your-team/your-project/settings/environment-variables# Production redirect URI
https://yourdomain.com/api/auth/callback/google
# Add to Google Cloud Console:
# https://console.cloud.google.com/apis/credentials# Deploy to production
vercel --prod
# Or push to main branch (with Git integration)
git push origin mainIf using Prisma with Vercel Postgres:
Connect to Vercel Postgres database
# Install Vercel Postgres
npm install @vercel/postgres
# Create database in Vercel dashboard
# Copy DATABASE_URL from Vercel
# Run migrations
npx prisma migrate deploy
# Generate Prisma Client
npx prisma generateBuild configuration for Amplify
version: 1
frontend:
phases:
preBuild:
commands:
- npm ci
build:
commands:
- npx prisma generate
- npx prisma migrate deploy
- npm run build
artifacts:
baseDirectory: .next
files:
- '**/*'
cache:
paths:
- node_modules/**/*
- .next/cache/**/*Set environment variables in Amplify console:
AUTH_SECRETGOOGLE_CLIENT_IDGOOGLE_CLIENT_SECRETGOOGLE_REDIRECT_URIDATABASE_URLDeploy to EC2 instance
#!/bin/bash
# Update system
sudo apt update && sudo apt upgrade -y
# Install Node.js
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejs
# Install PM2
sudo npm install -g pm2
# Clone repository
git clone https://github.com/your-org/your-app.git
cd your-app
# Install dependencies
npm ci
# Generate Prisma Client
npx prisma generate
# Run migrations
npx prisma migrate deploy
# Build application
npm run build
# Start with PM2
pm2 start npm --name "auth-app" -- start
# Save PM2 config
pm2 save
# Auto-start on reboot
pm2 startup# Create .env file
cat > .env << EOF
AUTH_SECRET=your-secret-here
GOOGLE_CLIENT_ID=your-client-id
GOOGLE_CLIENT_SECRET=your-client-secret
GOOGLE_REDIRECT_URI=https://yourdomain.com/api/auth/callback/google
DATABASE_URL=postgresql://user:pass@localhost:5432/db
NODE_ENV=production
EOF
# Secure the file
chmod 600 .envRailway provides simple deployment with built-in PostgreSQL:
npm install -g @railway/cli
railway loginrailway init
railway add postgresqlrailway variables set AUTH_SECRET=your-secret
railway variables set GOOGLE_CLIENT_ID=your-client-id
railway variables set GOOGLE_CLIENT_SECRET=your-secret
railway variables set GOOGLE_REDIRECT_URI=https://yourdomain.com/api/auth/callback/google
# DATABASE_URL is automatically set by Railwayrailway up
# Or connect to GitHub for auto-deployment
railway linkRender configuration
services:
- type: web
name: auth-app
env: node
region: oregon
plan: starter
buildCommand: npm ci && npx prisma generate && npx prisma migrate deploy && npm run build
startCommand: npm start
envVars:
- key: NODE_ENV
value: production
- key: AUTH_SECRET
generateValue: true
- key: GOOGLE_CLIENT_ID
sync: false
- key: GOOGLE_CLIENT_SECRET
sync: false
- key: GOOGLE_REDIRECT_URI
value: https://your-app.onrender.com/api/auth/callback/google
- key: DATABASE_URL
fromDatabase:
name: auth-db
property: connectionString
databases:
- name: auth-db
databaseName: auth
user: auth_user
plan: starterPush to GitHub and connect repository in Render dashboard.
Multi-stage Docker build
# Build stage
FROM node:20-alpine AS builder
WORKDIR /app
# Copy package files
COPY package*.json ./
COPY prisma ./prisma/
# Install dependencies
RUN npm ci
# Generate Prisma Client
RUN npx prisma generate
# Copy source
COPY . .
# Build application
RUN npm run build
# Production stage
FROM node:20-alpine AS runner
WORKDIR /app
# Copy built files
COPY --from=builder /app/package*.json ./
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/.next ./.next
COPY --from=builder /app/public ./public
COPY --from=builder /app/prisma ./prisma
# Set environment
ENV NODE_ENV=production
ENV PORT=3000
# Expose port
EXPOSE 3000
# Run migrations and start
CMD ["sh", "-c", "npx prisma migrate deploy && npm start"]Docker Compose with PostgreSQL
version: '3.8'
services:
app:
build: .
ports:
- "3000:3000"
environment:
- AUTH_SECRET=${AUTH_SECRET}
- GOOGLE_CLIENT_ID=${GOOGLE_CLIENT_ID}
- GOOGLE_CLIENT_SECRET=${GOOGLE_CLIENT_SECRET}
- GOOGLE_REDIRECT_URI=${GOOGLE_REDIRECT_URI}
- DATABASE_URL=postgresql://postgres:postgres@db:5432/auth
depends_on:
- db
restart: unless-stopped
db:
image: postgres:16-alpine
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
- POSTGRES_DB=auth
volumes:
- postgres_data:/var/lib/postgresql/data
restart: unless-stopped
volumes:
postgres_data:# Build and run
docker-compose up -d
# View logs
docker-compose logs -f
# Stop
docker-compose down# Required
AUTH_SECRET=<strong-random-secret-32-chars-min>
NODE_ENV=production
# OAuth Provider (example: Google)
GOOGLE_CLIENT_ID=<your-client-id>
GOOGLE_CLIENT_SECRET=<your-client-secret>
GOOGLE_REDIRECT_URI=https://yourdomain.com/api/auth/callback/google
# Database (if using adapter)
DATABASE_URL=postgresql://user:pass@host:5432/db
# Email (if using email provider)
RESEND_API_KEY=<your-resend-key>
# or SMTP
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USER=<your-email>
SMTP_PASS=<your-password>
# CAPTCHA (optional)
RECAPTCHA_SECRET_KEY=<your-secret-key>
# MCP/Warpy (optional)
WARPY_API_KEY=<your-api-key># Generate AUTH_SECRET
openssl rand -base64 32
# Or use Node.js
node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"# Development: Create migration
npx prisma migrate dev --name add_auth_tables
# Production: Apply migrations
npx prisma migrate deploy
# Reset database (WARNING: deletes all data)
npx prisma migrate resetGitHub Actions deployment
name: Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install dependencies
run: npm ci
- name: Generate Prisma Client
run: npx prisma generate
- name: Run migrations
run: npx prisma migrate deploy
env:
DATABASE_URL: ${{ secrets.DATABASE_URL }}
- name: Build
run: npm run build
- name: Deploy to Vercel
run: npx vercel --prod --token ${{ secrets.VERCEL_TOKEN }}
env:
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}Vercel automatically provisions SSL certificates for custom domains.
# Install Certbot
sudo apt install certbot python3-certbot-nginx
# Get certificate
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com
# Auto-renewal
sudo certbot renew --dry-runNginx reverse proxy with SSL
server {
listen 80;
server_name yourdomain.com www.yourdomain.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name yourdomain.com www.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
location / {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
}
}Track errors in production
import * as Sentry from "@sentry/nextjs";
Sentry.init({
dsn: process.env.SENTRY_DSN,
environment: process.env.NODE_ENV,
tracesSampleRate: 1.0,
});
// Wrap auth errors
try {
const result = await authenticate(config, request);
} catch (error) {
Sentry.captureException(error, {
tags: { context: "authentication" },
});
throw error;
}Production logging
import winston from "winston";
const logger = winston.createLogger({
level: process.env.LOG_LEVEL || "info",
format: winston.format.json(),
transports: [
new winston.transports.File({ filename: "error.log", level: "error" }),
new winston.transports.File({ filename: "combined.log" }),
],
});
if (process.env.NODE_ENV !== "production") {
logger.add(new winston.transports.Console({
format: winston.format.simple(),
}));
}
// Usage
logger.info("User authenticated", {
userId: session.user.id,
provider: "google",
timestamp: new Date().toISOString(),
});// prisma/schema.prisma
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
// Use connection pooling (Prisma Accelerate or PgBouncer)
// DATABASE_URL=postgresql://user:pass@host:5432/db?connection_limit=10Use Redis for fast session lookups in production:
import { RedisAdapter } from "./redis-adapter";
const config = {
secret: process.env.AUTH_SECRET!,
provider: google({ /* ... */ }),
adapter: RedisAdapter(process.env.REDIS_URL!),
};Monitor application health
// app/api/health/route.ts
import { NextRequest } from "next/server";
import { PrismaClient } from "@prisma/client";
const prisma = new PrismaClient();
export async function GET(request: NextRequest) {
try {
// Check database connection
await prisma.$queryRaw`SELECT 1`;
return Response.json({
status: "healthy",
timestamp: new Date().toISOString(),
uptime: process.uptime(),
});
} catch (error) {
return Response.json(
{
status: "unhealthy",
error: error.message,
timestamp: new Date().toISOString(),
},
{ status: 503 }
);
}
}# Create a backup before migrations
pg_dump $DATABASE_URL > backup-$(date +%Y%m%d-%H%M%S).sql
# If migration fails, restore from backup
psql $DATABASE_URL < backup-20240315-120000.sql
# Or use Prisma migrate resolve
npx prisma migrate resolve --rolled-back "20240315120000_migration_name"# Vercel: Instant rollback via dashboard or CLI
vercel rollback
# Railway: Rollback to previous deployment
railway rollback
# Docker: Use previous image
docker-compose down
docker-compose up -d --force-recreate your-app:previous-tagEnsure redirect URI matches exactly in provider settings:
# Check your production URL
echo $GOOGLE_REDIRECT_URI
# Should be: https://yourdomain.com/api/auth/callback/google
# NOT: http://... (wrong protocol)
# NOT: https://www.yourdomain.com/... (wrong subdomain)# Test database connection
npx prisma db pull
# Check connection string format
# postgresql://USER:PASSWORD@HOST:PORT/DATABASE?schema=public// Add validation
if (!process.env.AUTH_SECRET) {
throw new Error("AUTH_SECRET is required");
}
if (process.env.AUTH_SECRET.length < 32) {
throw new Error("AUTH_SECRET must be at least 32 characters");
}