Skip to content

Self-hosted: Email authentication not creating sessions after verification #1360

@FarhanSE

Description

@FarhanSE

Description

When using self-hosted(Digital Ocean Droplet) Cap Web with email authentication, users can successfully verify their email via OTP, but the authentication flow fails to create a session. After entering a valid OTP, users are redirected to /login-success which returns a 404 error, and no session is established.

Reproduction

  1. Start the Docker Compose stack: docker compose up -d
  2. Navigate to http://137.................. in a browser
  3. Enter an email address on the login page
  4. Enter the OTP code on the verification page
  5. Click "Verify"

After entering a valid OTP:

  1. NextAuth should create a session (adapter_createSession should be called)
  2. A session cookie should be set in the browser
  3. User should be redirected to the dashboard
  4. User should remain logged in

Additional Context

docker-compose.yml

version: "3.9"
services:
  cap-primary-db:
    image: mysql:8.0
    container_name: cap-primary-db
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: [REDACTED]
      MYSQL_DATABASE: capdb
      MYSQL_USER: capuser
      MYSQL_PASSWORD: [REDACTED]
    volumes:
      - cap-so-selfhost_ps-mysql:/var/lib/mysql
    ports:
      - "3307:3306"
    networks:
      - cap-network

  cap-minio-storage:
    image: minio/minio:latest
    container_name: cap-minio-storage
    restart: unless-stopped
    environment:
      MINIO_ROOT_USER: ${CAP_AWS_ACCESS_KEY}
      MINIO_ROOT_PASSWORD: ${CAP_AWS_SECRET_KEY}
      MINIO_DEFAULT_BUCKETS: ${CAP_AWS_BUCKET}
    volumes:
      - cap-so-selfhost_minio-data:/data
    ports:
      - "3902:3902"
    command: server /data --console-address ":9001" --address ":3902"
    networks:
      - cap-network

  cap-web:
    image: ghcr.io/capsoftware/cap-web:latest
    container_name: cap-web
    depends_on:
      - cap-primary-db
      - cap-minio-storage
    restart: unless-stopped
    env_file:
      - .env
    expose:
      - "3000"
    networks:
      - cap-network
    volumes:
      - ./uploads:/app/public/uploads

  cap-nginx:
    image: nginx:alpine
    container_name: cap-nginx
    restart: unless-stopped
    depends_on:
      - cap-web
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
    networks:
      - cap-network

volumes:
  cap-so-selfhost_ps-mysql:
  cap-so-selfhost_minio-data:

networks:
  cap-network:
    driver: bridge

.env

DATABASE CONFIG

DATABASE_URL=mysql://capuser:[REDACTED]@cap-primary-db:3306/capdb
DATABASE_ENCRYPTION_KEY=[REDACTED]

AUTH CONFIG

NEXTAUTH_SECRET=[REDACTED]
NEXTAUTH_URL=http://137.......
WEB_URL=http://137.184.........

STORAGE CONFIG

CAP_AWS_ACCESS_KEY=capS3root
CAP_AWS_SECRET_KEY=capS3root
CAP_AWS_BUCKET=capso
CAP_AWS_REGION=us-east-1
S3_PUBLIC_ENDPOINT=http://137.......:3902
S3_INTERNAL_ENDPOINT=http://cap-minio-storage:3902

EMAIL (RESEND) CONFIG

RESEND_API_KEY=[REDACTED]
RESEND_FROM_EMAIL=noreply@v...........m.com
RESEND_FROM_DOMAIN=va.............m.com

OTHER

NODE_ENV=production
CAP_TELEMETRY_DISABLED=true
NEXTAUTH_DEBUG=true

Logs:

cap-web  | [next-auth][warn][DEBUG_ENABLED] 
cap-web  | https://next-auth.js.org/warnings#debug_enabled
cap-web  | [next-auth][debug][adapter_getUserByEmail] { args: [ 'b..............@gmail.com' ] }
cap-web  | sendVerificationRequest
cap-web  | { identifier: 'b............@gmail.com', token: '957687' }
cap-web  | [next-auth][debug][adapter_createVerificationToken] {
cap-web  |   args: [
cap-web  |     {
cap-web  |       identifier: 'b...............@gmail.com',
cap-web  |       token: '39c0db562d59d28682f7dfa809f4c8ed2b746459987e482c830ce5f8da849113',
cap-web  |       expires: 2025-11-07T10:42:23.673Z
cap-web  |     }
cap-web  |   ]
cap-web  | }
cap-web  | {
cap-web  |   email: {
cap-web  |     '$$typeof': Symbol(react.transitional.element),
cap-web  |     type: {
cap-web  |       '$$typeof': Symbol(react.forward_ref),
cap-web  |       render: [Function (anonymous)],
cap-web  |       displayName: 'Html'
cap-web  |     },
cap-web  |     key: null,
cap-web  |     ref: null,
cap-web  |     props: { children: [Array] }
cap-web  |   }
cap-web  | }
cap-web  | [next-auth][warn][DEBUG_ENABLED] 
cap-web  | https://next-auth.js.org/warnings#debug_enabled
cap-web  | [next-auth][debug][adapter_useVerificationToken] {
cap-web  |   args: [
cap-web  |     {
cap-web  |       identifier: 'b..........@gmail.com',
cap-web  |       token: '39c0db562d59d28682f7dfa809f4c8ed2b746459987e482c830ce5f8da849113'
cap-web  |     }
cap-web  |   ]
cap-web  | }
cap-web  | [next-auth][debug][adapter_getUserByEmail] { args: [ 'b............@gmail.com' ] }
cap-web  | [next-auth][debug][adapter_getUserByEmail] { args: [ 'b............@gmail.com' ] }
cap-web  | [next-auth][debug][adapter_updateUser] {
cap-web  |   args: [
cap-web  |     { id: 'q1z9bk7n65hgk76', emailVerified: 2025-11-06T10:43:11.840Z }
cap-web  |   ]
cap-web  | }
cap-web  | timestamp=2025-11-06T10:43:12.260Z level=INFO fiber=#29 message="Using CAP_AWS_ACCESS_KEY and CAP_AWS_SECRET_KEY"

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions