From a12079649c5a68e1ef60554de15fbae5350e1761 Mon Sep 17 00:00:00 2001 From: zramsay Date: Tue, 11 Mar 2025 16:35:34 -0400 Subject: [PATCH] more debug --- package-lock.json | 92 ++++++++++++++- package.json | 2 + src/app/api/auth/[...nextauth]/route.ts | 145 +++++++++++++++++++----- src/app/api/debug/test-jwt/route.ts | 62 ++++++++++ src/app/debug/page.tsx | 72 +++++++++--- 5 files changed, 330 insertions(+), 43 deletions(-) create mode 100644 src/app/api/debug/test-jwt/route.ts diff --git a/package-lock.json b/package-lock.json index f70eaeb..e646c93 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,7 @@ "@solana/spl-token": "^0.3.8", "@solana/web3.js": "^1.78.4", "@supabase/supabase-js": "^2.49.1", + "@types/jsonwebtoken": "^9.0.9", "@types/multer": "^1.4.12", "axios": "^1.7.9", "browser-image-compression": "^2.0.2", @@ -21,6 +22,7 @@ "file-type": "^20.0.1", "form-data": "^4.0.1", "formidable": "^3.5.2", + "jsonwebtoken": "^9.0.2", "lucide-react": "^0.469.0", "multer": "^1.4.5-lts.1", "next": "^15.1.4", @@ -1178,6 +1180,15 @@ "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true }, + "node_modules/@types/jsonwebtoken": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.9.tgz", + "integrity": "sha512-uoe+GxEuHbvy12OUQct2X9JenKM3qAscquYymuQN4fMWG9DBQtykrQEFcAbVACF7qaLw9BePSodUL0kquqBJpQ==", + "dependencies": { + "@types/ms": "*", + "@types/node": "*" + } + }, "node_modules/@types/long": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz", @@ -1190,6 +1201,11 @@ "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", "license": "MIT" }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==" + }, "node_modules/@types/multer": { "version": "1.4.12", "resolved": "https://registry.npmjs.org/@types/multer/-/multer-1.4.12.tgz", @@ -4877,6 +4893,46 @@ "node": "*" } }, + "node_modules/jsonwebtoken": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jsonwebtoken/node_modules/jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jsonwebtoken/node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, "node_modules/jsx-ast-utils": { "version": "3.3.5", "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", @@ -4989,12 +5045,47 @@ "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", "license": "MIT" }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" + }, "node_modules/long": { "version": "5.2.3", "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", @@ -6342,7 +6433,6 @@ "version": "7.6.3", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "devOptional": true, "bin": { "semver": "bin/semver.js" }, diff --git a/package.json b/package.json index 2341877..f7ca1c4 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "@solana/spl-token": "^0.3.8", "@solana/web3.js": "^1.78.4", "@supabase/supabase-js": "^2.49.1", + "@types/jsonwebtoken": "^9.0.9", "@types/multer": "^1.4.12", "axios": "^1.7.9", "browser-image-compression": "^2.0.2", @@ -22,6 +23,7 @@ "file-type": "^20.0.1", "form-data": "^4.0.1", "formidable": "^3.5.2", + "jsonwebtoken": "^9.0.2", "lucide-react": "^0.469.0", "multer": "^1.4.5-lts.1", "next": "^15.1.4", diff --git a/src/app/api/auth/[...nextauth]/route.ts b/src/app/api/auth/[...nextauth]/route.ts index 45d3401..31520d1 100644 --- a/src/app/api/auth/[...nextauth]/route.ts +++ b/src/app/api/auth/[...nextauth]/route.ts @@ -89,6 +89,49 @@ const authOptions = { } }; +// Create detailed error response with full information +function createDetailedErrorResponse(title: string, error: any, req?: Request) { + const errorObj = error instanceof Error ? { + name: error.name, + message: error.message, + stack: error.stack?.split('\n').map(line => line.trim()), + } : String(error); + + const errorDetails = { + error: title, + timestamp: new Date().toISOString(), + details: errorObj, + request: req ? { + url: req.url, + method: req.method, + headers: { + host: req.headers.get('host'), + referer: req.headers.get('referer'), + 'user-agent': req.headers.get('user-agent'), + } + } : undefined, + env: { + node_env: process.env.NODE_ENV, + nextauth_url: process.env.NEXTAUTH_URL, + has_secret: !!process.env.NEXTAUTH_SECRET, + has_google: !!process.env.GOOGLE_CLIENT_ID && !!process.env.GOOGLE_CLIENT_SECRET, + } + }; + + console.error("AUTH ERROR DETAILS:", JSON.stringify(errorDetails, null, 2)); + + return new Response( + JSON.stringify(errorDetails), + { + status: 500, + headers: { + "Content-Type": "application/json", + "Cache-Control": "no-store, max-age=0" + } + } + ); +} + // Wrap NextAuth in a try-catch block to catch initialization errors let handler; try { @@ -96,27 +139,13 @@ try { console.log("NextAuth handler initialized successfully"); } catch (error) { console.error("CRITICAL ERROR: NextAuth initialization failed:", error); - // Create a fallback handler that logs the error and returns a 500 + // Create a fallback handler that returns detailed error information const errorHandler = { GET: async (req: Request) => { - console.error("NextAuth GET error handler triggered for URL:", req.url); - return new Response( - JSON.stringify({ - error: "Auth system initialization failed", - message: "Check server logs" - }), - { status: 500, headers: { "Content-Type": "application/json" } } - ); + return createDetailedErrorResponse("Auth system initialization failed", error, req); }, POST: async (req: Request) => { - console.error("NextAuth POST error handler triggered for URL:", req.url); - return new Response( - JSON.stringify({ - error: "Auth system initialization failed", - message: "Check server logs" - }), - { status: 500, headers: { "Content-Type": "application/json" } } - ); + return createDetailedErrorResponse("Auth system initialization failed", error, req); } }; handler = { handlers: errorHandler }; @@ -125,24 +154,82 @@ try { // Export handlers with additional error handling export async function GET(req: Request) { try { - return await handler.handlers.GET(req); + // Check for debug header + const isDebug = req.headers.get('x-debug-info') === 'true'; + if (isDebug) { + console.log('DEBUG request to NextAuth endpoint:', req.url); + console.log('DEBUG Headers:', + [...req.headers.entries()].reduce((obj, [key, val]) => { + obj[key] = val; + return obj; + }, {} as Record) + ); + } + + try { + // Attempt to handle the request + return await handler.handlers.GET(req); + } catch (error) { + console.error('NextAuth GET handler error:', error); + + // If there's a debug header, also send the error information in the response + if (isDebug) { + return createDetailedErrorResponse("NextAuth GET operation failed", error, req); + } + + // Otherwise, return a standard NextAuth error + return new Response( + JSON.stringify({ + error: "Failed to handle authentication request", + message: error instanceof Error ? error.message : String(error) + }), + { status: 500, headers: { "Content-Type": "application/json" } } + ); + } } catch (error) { - console.error("NextAuth GET error:", error); - return new Response( - JSON.stringify({ error: "Auth operation failed", details: String(error) }), - { status: 500, headers: { "Content-Type": "application/json" } } - ); + // This catches errors in our error handling + console.error('Critical error in NextAuth GET wrapper:', error); + return createDetailedErrorResponse("Critical NextAuth error", error, req); } } export async function POST(req: Request) { try { - return await handler.handlers.POST(req); + // Check for debug header + const isDebug = req.headers.get('x-debug-info') === 'true'; + if (isDebug) { + console.log('DEBUG request to NextAuth POST endpoint:', req.url); + console.log('DEBUG Headers:', + [...req.headers.entries()].reduce((obj, [key, val]) => { + obj[key] = val; + return obj; + }, {} as Record) + ); + } + + try { + // Attempt to handle the request + return await handler.handlers.POST(req); + } catch (error) { + console.error('NextAuth POST handler error:', error); + + // If there's a debug header, also send the error information in the response + if (isDebug) { + return createDetailedErrorResponse("NextAuth POST operation failed", error, req); + } + + // Otherwise, return a standard NextAuth error + return new Response( + JSON.stringify({ + error: "Failed to handle authentication request", + message: error instanceof Error ? error.message : String(error) + }), + { status: 500, headers: { "Content-Type": "application/json" } } + ); + } } catch (error) { - console.error("NextAuth POST error:", error); - return new Response( - JSON.stringify({ error: "Auth operation failed", details: String(error) }), - { status: 500, headers: { "Content-Type": "application/json" } } - ); + // This catches errors in our error handling + console.error('Critical error in NextAuth POST wrapper:', error); + return createDetailedErrorResponse("Critical NextAuth error", error, req); } } \ No newline at end of file diff --git a/src/app/api/debug/test-jwt/route.ts b/src/app/api/debug/test-jwt/route.ts new file mode 100644 index 0000000..f2f01c5 --- /dev/null +++ b/src/app/api/debug/test-jwt/route.ts @@ -0,0 +1,62 @@ +import { NextRequest, NextResponse } from 'next/server'; +import * as jwt from 'jsonwebtoken'; + +export async function GET(request: NextRequest) { + try { + // Test if we can sign and verify JWTs - this is a common issue with NextAuth + const testObj = { test: 'data', timestamp: Date.now() }; + let jwtResults = {}; + + if (process.env.NEXTAUTH_SECRET) { + try { + // Try to sign a token with the secret + const token = jwt.sign(testObj, process.env.NEXTAUTH_SECRET, { expiresIn: '5m' }); + + // Try to verify the token + const decoded = jwt.verify(token, process.env.NEXTAUTH_SECRET); + + jwtResults = { + signed: true, + verified: true, + token_excerpt: `${token.substring(0, 20)}...`, + decoded + }; + } catch (jwtError) { + jwtResults = { + error: String(jwtError), + signed: false, + verified: false + }; + } + } else { + jwtResults = { + error: 'NEXTAUTH_SECRET is not defined', + signed: false, + verified: false + }; + } + + // Test cookie functionality + const cookieTest = { + can_set_cookies: true, + settings: { + secure: process.env.NODE_ENV === 'production', + domain: new URL(process.env.NEXTAUTH_URL || `https://${request.headers.get('host')}`).hostname, + } + }; + + return NextResponse.json({ + success: true, + jwt_test: jwtResults, + cookie_test: cookieTest, + timestamp: new Date().toISOString(), + }); + } catch (error) { + console.error('JWT test error:', error); + return NextResponse.json({ + success: false, + error: String(error), + stack: error instanceof Error ? error.stack : undefined + }, { status: 500 }); + } +}; \ No newline at end of file diff --git a/src/app/debug/page.tsx b/src/app/debug/page.tsx index ab61ef8..a34a3a8 100644 --- a/src/app/debug/page.tsx +++ b/src/app/debug/page.tsx @@ -10,31 +10,55 @@ export default function DebugPage() { const [authData, setAuthData] = useState(null); const [serverEnv, setServerEnv] = useState(null); const [authCheck, setAuthCheck] = useState(null); + const [jwtTest, setJwtTest] = useState(null); const [authError, setAuthError] = useState(null); useEffect(() => { const checkAuth = async () => { try { - const res = await fetch('/api/auth/session'); + // Let's make a specific fetch with all details for debugging + const res = await fetch('/api/auth/session', { + method: 'GET', + credentials: 'include', + headers: { + 'Accept': 'application/json', + 'X-Debug-Info': 'true' + } + }); + + // Get the response text first for debugging + const responseText = await res.text(); + console.log('Auth session raw response:', responseText); + if (res.ok) { - const data = await res.json(); - setAuthData(data); - } else { - setAuthError(`Session API error: ${res.status} ${res.statusText}`); - // Try to get error details from body try { - const errorData = await res.json(); - console.error('Auth session error details:', errorData); - if (errorData.error) { - setAuthError(prev => `${prev} - ${errorData.error}`); - } + const data = JSON.parse(responseText); + setAuthData(data); } catch (e) { - // Couldn't parse body + setAuthError(`Session API returned invalid JSON: ${responseText.substring(0, 100)}`); + } + } else { + // Create detailed error information + let errorInfo = `Session API error: ${res.status} ${res.statusText}`; + + // Add response body for debugging + if (responseText) { + try { + const errorData = JSON.parse(responseText); + console.error('Auth session error details:', errorData); + setAuthError(`${errorInfo}\n\nDetails: ${JSON.stringify(errorData, null, 2)}`); + } catch (e) { + // Not JSON, use raw text + errorInfo += `\n\nResponse: ${responseText.substring(0, 500)}`; + setAuthError(errorInfo); + } + } else { + setAuthError(errorInfo + " (No response body)"); } } } catch (error) { console.error('Error fetching auth session', error); - setAuthError(String(error)); + setAuthError(`Exception: ${String(error)}`); } }; @@ -66,9 +90,24 @@ export default function DebugPage() { } }; + const testJwtFunctionality = async () => { + try { + const res = await fetch('/api/debug/test-jwt'); + if (res.ok) { + const data = await res.json(); + setJwtTest(data); + } else { + console.error('Failed to test JWT functionality:', res.statusText); + } + } catch (error) { + console.error('Error testing JWT functionality:', error); + } + }; + checkAuth(); checkServerEnv(); checkAuthConfig(); + testJwtFunctionality(); }, []); // Environment variables check (public variables only) @@ -122,6 +161,13 @@ export default function DebugPage() { +
+

JWT Functionality Test

+
+              {jwtTest ? JSON.stringify(jwtTest, null, 2) : "Testing JWT functionality..."}
+            
+
+

Client Environment Variables