From b78ac2bc55b3f6528e844874ae01e25933e7856c Mon Sep 17 00:00:00 2001 From: aamoghS Date: Sun, 15 Feb 2026 15:15:19 -0500 Subject: [PATCH] quick test --- packages/db/scripts/diagnose-auth.ts | 102 ++++++++++++++++++ .../app/(portal)/api/debug-auth/route.ts | 46 ++++++++ 2 files changed, 148 insertions(+) create mode 100644 packages/db/scripts/diagnose-auth.ts create mode 100644 sites/mainweb/app/(portal)/api/debug-auth/route.ts diff --git a/packages/db/scripts/diagnose-auth.ts b/packages/db/scripts/diagnose-auth.ts new file mode 100644 index 0000000..6b2ff51 --- /dev/null +++ b/packages/db/scripts/diagnose-auth.ts @@ -0,0 +1,102 @@ +import { drizzle } from "drizzle-orm/node-postgres"; +import { Pool } from "pg"; +import { createHash } from "crypto"; +import * as dotenv from "dotenv"; +import path from "path"; +import { eq, and } from "drizzle-orm"; + +dotenv.config({ path: path.resolve(__dirname, "../../../.env") }); + +import { verificationTokens } from "../src/schemas"; + +const DATABASE_URL = process.env.DATABASE_URL; +const AUTH_SECRET = process.env.AUTH_SECRET || process.env.NEXTAUTH_SECRET; + +if (!DATABASE_URL) throw new Error("DATABASE_URL is not defined"); +if (!AUTH_SECRET) throw new Error("AUTH_SECRET/NEXTAUTH_SECRET is not defined"); + +const pool = new Pool({ connectionString: DATABASE_URL }); +const db = drizzle(pool); + +async function diagnose() { + console.log("=== NextAuth Email Verification Diagnostic ===\n"); + console.log(`AUTH_SECRET present: ${!!AUTH_SECRET}`); + console.log(`AUTH_SECRET (first 10 chars): ${AUTH_SECRET!.substring(0, 10)}...`); + console.log(`DATABASE_URL present: ${!!DATABASE_URL}\n`); + + // Step 1: Check existing tokens + console.log("--- Step 1: Checking existing verification tokens ---"); + const existingTokens = await db.select().from(verificationTokens); + console.log(`Found ${existingTokens.length} existing token(s).`); + for (const t of existingTokens) { + const isExpired = new Date(t.expires) < new Date(); + console.log(` identifier: ${t.identifier}, expired: ${isExpired}, token_hash_start: ${t.token.substring(0, 20)}...`); + } + + // Step 2: Simulate creating a verification token + console.log("\n--- Step 2: Simulating token creation ---"); + const rawToken = "test_diagnostic_token_12345"; + const testEmail = "diagnostic@test.com"; + const hashedToken = createHash("sha256") + .update(`${rawToken}${AUTH_SECRET}`) + .digest("hex"); + const expires = new Date(Date.now() + 86400 * 1000); // 24 hours + + console.log(`Raw token: ${rawToken}`); + console.log(`Hashed token: ${hashedToken}`); + console.log(`Identifier: ${testEmail}`); + console.log(`Expires: ${expires.toISOString()}`); + + try { + await db.insert(verificationTokens).values({ + identifier: testEmail, + token: hashedToken, + expires, + }); + console.log("✅ Token inserted successfully"); + } catch (err: any) { + console.log(`❌ Failed to insert token: ${err.message}`); + await pool.end(); + return; + } + + // Step 3: Simulate verification (lookup + delete) + console.log("\n--- Step 3: Simulating token verification ---"); + const reHashedToken = createHash("sha256") + .update(`${rawToken}${AUTH_SECRET}`) + .digest("hex"); + + console.log(`Re-hashed token: ${reHashedToken}`); + console.log(`Hashes match: ${hashedToken === reHashedToken}`); + + try { + const result = await db + .delete(verificationTokens) + .where( + and( + eq(verificationTokens.identifier, testEmail), + eq(verificationTokens.token, reHashedToken) + ) + ) + .returning(); + + if (result.length > 0) { + console.log("✅ Token found and deleted successfully — verification WOULD work!"); + } else { + console.log("❌ Token NOT found — verification WOULD fail!"); + console.log(" This means the hash comparison is failing in the DB"); + } + } catch (err: any) { + console.log(`❌ Error during verification: ${err.message}`); + } + + // Step 4: Re-check if the token was cleaned up + console.log("\n--- Step 4: Post-cleanup check ---"); + const remaining = await db.select().from(verificationTokens); + console.log(`Remaining tokens: ${remaining.length}`); + + console.log("\n=== Diagnostic complete ==="); + await pool.end(); +} + +diagnose().catch(console.error); diff --git a/sites/mainweb/app/(portal)/api/debug-auth/route.ts b/sites/mainweb/app/(portal)/api/debug-auth/route.ts new file mode 100644 index 0000000..193fe86 --- /dev/null +++ b/sites/mainweb/app/(portal)/api/debug-auth/route.ts @@ -0,0 +1,46 @@ +import { NextResponse } from "next/server"; +import { createHash } from "crypto"; + +// Temporary debug endpoint to check auth configuration +// DELETE THIS AFTER DEBUGGING +export async function GET() { + const authSecret = process.env.AUTH_SECRET; + const nextAuthSecret = process.env.NEXTAUTH_SECRET; + const nextAuthUrl = process.env.NEXTAUTH_URL; + const authUrl = process.env.AUTH_URL; + const dbUrl = process.env.DATABASE_URL; + const emailHost = process.env.EMAIL_SERVER_HOST; + const emailUser = process.env.EMAIL_SERVER_USER; + const emailPass = process.env.EMAIL_SERVER_PASSWORD; + + // Test hash with each secret + const testToken = "test123"; + const hashWithAuth = authSecret + ? createHash("sha256").update(`${testToken}${authSecret}`).digest("hex").substring(0, 16) + : "N/A"; + const hashWithNextAuth = nextAuthSecret + ? createHash("sha256").update(`${testToken}${nextAuthSecret}`).digest("hex").substring(0, 16) + : "N/A"; + + return NextResponse.json({ + env: { + AUTH_SECRET_set: !!authSecret, + AUTH_SECRET_first5: authSecret ? authSecret.substring(0, 5) : null, + NEXTAUTH_SECRET_set: !!nextAuthSecret, + NEXTAUTH_SECRET_first5: nextAuthSecret ? nextAuthSecret.substring(0, 5) : null, + NEXTAUTH_URL: nextAuthUrl, + AUTH_URL: authUrl, + DATABASE_URL_set: !!dbUrl, + EMAIL_HOST: emailHost, + EMAIL_USER: emailUser, + EMAIL_PASS_set: !!emailPass, + secrets_match: authSecret === nextAuthSecret, + }, + hash_test: { + with_AUTH_SECRET: hashWithAuth, + with_NEXTAUTH_SECRET: hashWithNextAuth, + hashes_match: hashWithAuth === hashWithNextAuth, + }, + node_env: process.env.NODE_ENV, + }); +}