Deployment Guide

Deploy your authentication system to production

Deployment Guide

This guide covers deploying applications using @warpy-auth-sdk/core to popular hosting platforms with production-ready configurations.

Pre-Deployment Checklist

  • ✓ Generate strong AUTH_SECRET (32+ characters)
  • ✓ Configure OAuth providers with production redirect URIs
  • ✓ Set up production database (if using adapter)
  • ✓ Enable HTTPS on your domain
  • ✓ Configure environment variables
  • ✓ Test authentication flows in staging
  • ✓ Review security best practices
  • ✓ Set up monitoring and logging

Vercel Deployment

Vercel is the recommended platform for Next.js applications.

1. Install Vercel CLI

npm install -g vercel
# or use npx
npx vercel

2. Environment Variables

Set 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

3. Configure OAuth Redirect URIs

# Production redirect URI
https://yourdomain.com/api/auth/callback/google

# Add to Google Cloud Console:
# https://console.cloud.google.com/apis/credentials

4. Deploy

# Deploy to production
vercel --prod

# Or push to main branch (with Git integration)
git push origin main

5. Database Setup (Optional)

If using Prisma with Vercel Postgres:

Vercel Postgres Setup

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 generate

AWS Deployment

AWS Amplify (Next.js)

amplify.yml

Build 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_SECRET
  • GOOGLE_CLIENT_ID
  • GOOGLE_CLIENT_SECRET
  • GOOGLE_REDIRECT_URI
  • DATABASE_URL

AWS EC2 (Node.js)

EC2 Deployment Script

Deploy 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

Environment Variables on EC2

# 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 .env

Railway Deployment

Railway provides simple deployment with built-in PostgreSQL:

1. Install Railway CLI

npm install -g @railway/cli
railway login

2. Create Project

railway init
railway add postgresql

3. Set Environment Variables

railway 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 Railway

4. Deploy

railway up

# Or connect to GitHub for auto-deployment
railway link

Render Deployment

1. Create render.yaml

render.yaml

Render 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: starter

2. Deploy

Push to GitHub and connect repository in Render dashboard.

Docker Deployment

Dockerfile

Dockerfile

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

docker-compose.yml

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:

Deploy with Docker

# Build and run
docker-compose up -d

# View logs
docker-compose logs -f

# Stop
docker-compose down

Environment Configuration

Production Environment Variables

# 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 Secrets

# Generate AUTH_SECRET
openssl rand -base64 32

# Or use Node.js
node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"

Database Migrations

Prisma Migrations

# 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 reset

Migration in CI/CD

.github/workflows/deploy.yml

GitHub 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 }}

SSL/HTTPS Setup

Vercel (Automatic)

Vercel automatically provisions SSL certificates for custom domains.

Let's Encrypt (Self-Hosted)

# 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-run

Nginx Configuration

/etc/nginx/sites-available/yourdomain.com

Nginx 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;
  }
}

Monitoring and Logging

Sentry Error Tracking

Sentry Integration

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;
}

Structured Logging

Winston Logger

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(),
});

Performance Optimization

Database Connection Pooling

// 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=10

Redis for Sessions

Use 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!),
};

Health Checks

Health Check Endpoint

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 }
    );
  }
}

Rollback Strategy

Database Rollbacks

# 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"

Application Rollbacks

# 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-tag

Troubleshooting

OAuth Redirect Mismatch

Ensure 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)

Database Connection Issues

# Test database connection
npx prisma db pull

# Check connection string format
# postgresql://USER:PASSWORD@HOST:PORT/DATABASE?schema=public

Environment Variable Not Set

// 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");
}

Post-Deployment

  • ✓ Test all authentication flows (OAuth, email, etc.)
  • ✓ Verify session persistence across requests
  • ✓ Test sign-out functionality
  • ✓ Check error logging and monitoring
  • ✓ Verify HTTPS on all pages
  • ✓ Test protected routes
  • ✓ Monitor performance and errors
  • ✓ Set up automated backups

Next Steps

Deployment | @warpy-auth-sdk/core