Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 38 additions & 1 deletion packages/auth/src/adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,49 @@ function createAdapter(): Adapter | undefined {
}

try {
return DrizzleAdapter(db, {
const baseAdapter = DrizzleAdapter(db, {
usersTable: users,
accountsTable: accounts,
sessionsTable: sessions,
verificationTokensTable: verificationTokens,
});

// DEBUG: Wrap token methods with logging
const wrappedAdapter: Adapter = {
...baseAdapter,
async createVerificationToken(data) {
console.log("[AUTH-DEBUG] createVerificationToken called:", {
identifier: data.identifier,
tokenHash: data.token?.substring(0, 20) + "...",
expires: data.expires,
});
const result = await baseAdapter.createVerificationToken!(data);
console.log("[AUTH-DEBUG] createVerificationToken result:", result ? "SUCCESS" : "NULL");
return result;
},
async useVerificationToken(params) {
console.log("[AUTH-DEBUG] useVerificationToken called:", {
identifier: params.identifier,
tokenHash: params.token?.substring(0, 20) + "...",
});
const result = await baseAdapter.useVerificationToken!(params);
console.log("[AUTH-DEBUG] useVerificationToken result:", result ? "FOUND" : "NOT_FOUND (THIS CAUSES VERIFICATION_FAILED)");
if (!result) {
// Extra debug: check if any tokens exist for this identifier
const { eq } = await import("drizzle-orm");
const existing = await db.select().from(verificationTokens).where(eq(verificationTokens.identifier, params.identifier));
console.log("[AUTH-DEBUG] tokens for this identifier:", existing.length);
if (existing.length > 0) {
console.log("[AUTH-DEBUG] stored token starts with:", existing[0].token?.substring(0, 20));
console.log("[AUTH-DEBUG] lookup token starts with:", params.token?.substring(0, 20));
console.log("[AUTH-DEBUG] tokens match:", existing[0].token === params.token);
}
}
return result;
},
};

return wrappedAdapter;
} catch (error) {
console.error("Auth adapter: Failed to create Drizzle adapter:", error);
return undefined;
Expand Down
112 changes: 71 additions & 41 deletions sites/mainweb/app/(portal)/api/debug-auth/route.ts
Original file line number Diff line number Diff line change
@@ -1,46 +1,76 @@
import { NextResponse } from "next/server";
import { createHash } from "crypto";
import { db, verificationTokens } from "@query/db";
import { eq, and } from "drizzle-orm";

// Temporary debug endpoint to check auth configuration
// Temporary debug endpoint — tests the complete token flow
// 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,
});
const logs: string[] = [];

try {
// Step 1: Generate a test token the same way NextAuth does (Web Crypto)
const rawToken = "debug_test_" + Date.now();
const secret = process.env.AUTH_SECRET || process.env.NEXTAUTH_SECRET || "";
const testEmail = "debug_test@test.com";

logs.push(`Raw token: ${rawToken}`);
logs.push(`Secret first 5: ${secret.substring(0, 5)}`);

// Hash using Web Crypto (same as @auth/core createHash)
const data = new TextEncoder().encode(`${rawToken}${secret}`);
const hashBuffer = await crypto.subtle.digest("SHA-256", data);
const hashedToken = Array.from(new Uint8Array(hashBuffer))
.map((b) => b.toString(16).padStart(2, "0"))
.join("");

logs.push(`Hashed token: ${hashedToken.substring(0, 30)}...`);

// Step 2: Insert token into DB
try {
await db.insert(verificationTokens).values({
identifier: testEmail,
token: hashedToken,
expires: new Date(Date.now() + 86400000),
});
logs.push("✅ Insert: SUCCESS");
} catch (e: any) {
logs.push(`❌ Insert: FAILED — ${e.message}`);
return NextResponse.json({ logs, status: "INSERT_FAILED" });
}

// Step 3: Look up token (same as useVerificationToken)
try {
const result = await db
.delete(verificationTokens)
.where(
and(
eq(verificationTokens.identifier, testEmail),
eq(verificationTokens.token, hashedToken)
)
)
.returning();

if (result.length > 0) {
logs.push("✅ Lookup: FOUND AND DELETED — token flow WORKS");
} else {
logs.push("❌ Lookup: NOT FOUND — this is the bug!");
}
} catch (e: any) {
logs.push(`❌ Lookup: ERROR — ${e.message}`);
}

// Step 4: Check if there are ANY tokens currently in the DB
const allTokens = await db.select().from(verificationTokens);
logs.push(`\nAll tokens in DB: ${allTokens.length}`);
for (const t of allTokens) {
const expired = new Date(t.expires) < new Date();
logs.push(` - ${t.identifier} | hash: ${t.token.substring(0, 16)}... | expired: ${expired}`);
}

return NextResponse.json({ logs, status: "COMPLETE" });

} catch (e: any) {
logs.push(`Fatal error: ${e.message}`);
return NextResponse.json({ logs, status: "ERROR" });
}
}
Loading