develop #83
46
susconecta/app/api/signin-user/route.ts
Normal file
46
susconecta/app/api/signin-user/route.ts
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
import { NextResponse } from 'next/server';
|
||||||
|
import { ENV_CONFIG } from '@/lib/env-config';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Proxy server-side route (App Router) to call Supabase OpenAPI /auth/v1/signin
|
||||||
|
* This keeps the Supabase anon key on the server and avoids CORS from browsers.
|
||||||
|
*/
|
||||||
|
export async function POST(req: Request) {
|
||||||
|
try {
|
||||||
|
const payload = await req.json();
|
||||||
|
|
||||||
|
// Lightweight, non-sensitive debug logging to verify the proxy is hit at runtime.
|
||||||
|
try {
|
||||||
|
console.log('[api/signin-user] POST received', {
|
||||||
|
url: typeof (req as any).url === 'string' ? (req as any).url : undefined,
|
||||||
|
email: payload?.email ?? null,
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
// never throw from logging
|
||||||
|
}
|
||||||
|
|
||||||
|
const url = `${ENV_CONFIG.SUPABASE_URL}/auth/v1/signin`;
|
||||||
|
|
||||||
|
const response = await fetch(url, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
apikey: ENV_CONFIG.SUPABASE_ANON_KEY,
|
||||||
|
},
|
||||||
|
body: JSON.stringify(payload),
|
||||||
|
});
|
||||||
|
|
||||||
|
const text = await response.text();
|
||||||
|
let data: any = null;
|
||||||
|
try {
|
||||||
|
data = text ? JSON.parse(text) : null;
|
||||||
|
} catch (e) {
|
||||||
|
data = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NextResponse.json(data, { status: response.status });
|
||||||
|
} catch (error) {
|
||||||
|
console.error('[api/signin-user] Unexpected error', error);
|
||||||
|
return NextResponse.json({ error: 'Internal proxy error' }, { status: 500 });
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -89,7 +89,10 @@ export async function loginUser(
|
|||||||
password: string,
|
password: string,
|
||||||
userType: 'profissional' | 'paciente' | 'administrador'
|
userType: 'profissional' | 'paciente' | 'administrador'
|
||||||
): Promise<LoginResponse> {
|
): Promise<LoginResponse> {
|
||||||
let url = AUTH_ENDPOINTS.LOGIN;
|
// Use server-side AUTH_ENDPOINTS.LOGIN by default. When running in the browser
|
||||||
|
// prefer the local proxy that forwards to the OpenAPI signin: `/api/signin-user`.
|
||||||
|
const isBrowser = typeof window !== 'undefined';
|
||||||
|
const url = isBrowser ? '/api/signin-user' : AUTH_ENDPOINTS.LOGIN;
|
||||||
|
|
||||||
const payload = {
|
const payload = {
|
||||||
email,
|
email,
|
||||||
@ -104,9 +107,9 @@ export async function loginUser(
|
|||||||
timestamp: new Date().toLocaleTimeString()
|
timestamp: new Date().toLocaleTimeString()
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log('🔑 [AUTH-API] Credenciais sendo usadas no login:');
|
// Log only non-sensitive info; never log passwords
|
||||||
|
console.log('🔑 [AUTH-API] Credenciais sendo usadas no login (redacted):');
|
||||||
console.log('📧 Email:', email);
|
console.log('📧 Email:', email);
|
||||||
console.log('🔐 Senha:', password);
|
|
||||||
console.log('👤 UserType:', userType);
|
console.log('👤 UserType:', userType);
|
||||||
|
|
||||||
// Delay para visualizar na aba Network
|
// Delay para visualizar na aba Network
|
||||||
@ -118,11 +121,48 @@ export async function loginUser(
|
|||||||
// Debug: Log request sem credenciais sensíveis
|
// Debug: Log request sem credenciais sensíveis
|
||||||
debugRequest('POST', url, getLoginHeaders(), payload);
|
debugRequest('POST', url, getLoginHeaders(), payload);
|
||||||
|
|
||||||
const response = await fetch(url, {
|
// Helper to perform a login fetch and return response (no processing here)
|
||||||
|
async function doLoginFetch(targetUrl: string) {
|
||||||
|
try {
|
||||||
|
return await fetch(targetUrl, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: getLoginHeaders(),
|
headers: getLoginHeaders(),
|
||||||
body: JSON.stringify(payload),
|
body: JSON.stringify(payload),
|
||||||
});
|
});
|
||||||
|
} catch (err) {
|
||||||
|
// bubble up the error to the caller
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let response: Response;
|
||||||
|
try {
|
||||||
|
response = await doLoginFetch(url);
|
||||||
|
} catch (networkError) {
|
||||||
|
console.warn('[AUTH-API] Network error when calling', url, networkError);
|
||||||
|
// Try fallback to server endpoints if available
|
||||||
|
const fallback1 = AUTH_ENDPOINTS.LOGIN;
|
||||||
|
const fallback2 = `${ENV_CONFIG.SUPABASE_URL}/auth/v1/signin`;
|
||||||
|
let tried = [] as string[];
|
||||||
|
|
||||||
|
try {
|
||||||
|
tried.push(fallback1);
|
||||||
|
response = await doLoginFetch(fallback1);
|
||||||
|
} catch (e1) {
|
||||||
|
console.warn('[AUTH-API] Fallback1 failed', fallback1, e1);
|
||||||
|
try {
|
||||||
|
tried.push(fallback2);
|
||||||
|
response = await doLoginFetch(fallback2);
|
||||||
|
} catch (e2) {
|
||||||
|
console.error('[AUTH-API] All fallbacks failed', { tried, e1, e2 });
|
||||||
|
throw new AuthenticationError(
|
||||||
|
'Não foi possível contatar o serviço de autenticação (todos os caminhos falharam)',
|
||||||
|
'AUTH_NETWORK_ERROR',
|
||||||
|
{ tried }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
console.log(`[AUTH-API] Login response: ${response.status} ${response.statusText}`, {
|
console.log(`[AUTH-API] Login response: ${response.status} ${response.statusText}`, {
|
||||||
url: response.url,
|
url: response.url,
|
||||||
@ -130,6 +170,34 @@ export async function loginUser(
|
|||||||
timestamp: new Date().toLocaleTimeString()
|
timestamp: new Date().toLocaleTimeString()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// If proxy returned 404, try direct fallbacks (in case the proxy route is missing)
|
||||||
|
if (response.status === 404) {
|
||||||
|
console.warn('[AUTH-API] Proxy returned 404, attempting direct login fallbacks');
|
||||||
|
const fallback1 = AUTH_ENDPOINTS.LOGIN;
|
||||||
|
const fallback2 = `${ENV_CONFIG.SUPABASE_URL}/auth/v1/signin`;
|
||||||
|
let fallbackResponse: Response | null = null;
|
||||||
|
try {
|
||||||
|
fallbackResponse = await doLoginFetch(fallback1);
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('[AUTH-API] fallback1 failed', fallback1, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fallbackResponse || fallbackResponse.status === 404) {
|
||||||
|
try {
|
||||||
|
fallbackResponse = await doLoginFetch(fallback2);
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('[AUTH-API] fallback2 failed', fallback2, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fallbackResponse) {
|
||||||
|
response = fallbackResponse;
|
||||||
|
console.log('[AUTH-API] Used fallback response', { url: response.url, status: response.status });
|
||||||
|
} else {
|
||||||
|
console.error('[AUTH-API] No fallback produced a valid response');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Se falhar, mostrar detalhes do erro
|
// Se falhar, mostrar detalhes do erro
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
try {
|
try {
|
||||||
@ -148,6 +216,16 @@ export async function loginUser(
|
|||||||
// Delay adicional para ver status code
|
// Delay adicional para ver status code
|
||||||
await new Promise(resolve => setTimeout(resolve, 50));
|
await new Promise(resolve => setTimeout(resolve, 50));
|
||||||
|
|
||||||
|
// If after trying fallbacks we still have a 404, make the error explicit and actionable
|
||||||
|
if (response.status === 404) {
|
||||||
|
console.error('[AUTH-API] Final response was 404 (Not Found). Likely the local proxy route is missing or Next dev server is not running.', { url: response.url });
|
||||||
|
throw new AuthenticationError(
|
||||||
|
'Signin endpoint not found (404). Ensure Next.js dev server is running and the route `/api/signin-user` exists.',
|
||||||
|
'SIGNIN_NOT_FOUND',
|
||||||
|
{ url: response.url }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const data = await processResponse<any>(response);
|
const data = await processResponse<any>(response);
|
||||||
|
|
||||||
console.log('[AUTH] Dados recebidos da API:', data);
|
console.log('[AUTH] Dados recebidos da API:', data);
|
||||||
|
|||||||
@ -9,7 +9,6 @@ export function debugRequest(
|
|||||||
body?: any
|
body?: any
|
||||||
) {
|
) {
|
||||||
if (process.env.NODE_ENV !== 'development') return;
|
if (process.env.NODE_ENV !== 'development') return;
|
||||||
|
|
||||||
const headersWithoutSensitive = Object.keys(headers).reduce((acc, key) => {
|
const headersWithoutSensitive = Object.keys(headers).reduce((acc, key) => {
|
||||||
// Não logar valores sensíveis, apenas nomes
|
// Não logar valores sensíveis, apenas nomes
|
||||||
if (key.toLowerCase().includes('apikey') || key.toLowerCase().includes('authorization')) {
|
if (key.toLowerCase().includes('apikey') || key.toLowerCase().includes('authorization')) {
|
||||||
@ -20,15 +19,35 @@ export function debugRequest(
|
|||||||
return acc;
|
return acc;
|
||||||
}, {} as Record<string, string>);
|
}, {} as Record<string, string>);
|
||||||
|
|
||||||
const bodyShape = body ? Object.keys(typeof body === 'string' ? JSON.parse(body) : body) : [];
|
const bodyShape = body ? Object.keys(typeof body === 'string' ? (() => {
|
||||||
|
try { return JSON.parse(body); } catch { return {}; }
|
||||||
|
})() : body) : [];
|
||||||
|
|
||||||
|
// Support relative URLs (e.g. '/api/signin-user') by providing a base when needed.
|
||||||
|
try {
|
||||||
|
let urlObj: URL;
|
||||||
|
try {
|
||||||
|
urlObj = new URL(url);
|
||||||
|
} catch (e) {
|
||||||
|
// Fallbacks: browser origin or localhost for server-side dev
|
||||||
|
const base = (typeof window !== 'undefined' && window.location && window.location.origin)
|
||||||
|
? window.location.origin
|
||||||
|
: 'http://localhost';
|
||||||
|
urlObj = new URL(url, base);
|
||||||
|
}
|
||||||
|
|
||||||
console.log('[DEBUG] Request Preview:', {
|
console.log('[DEBUG] Request Preview:', {
|
||||||
method,
|
method,
|
||||||
path: new URL(url).pathname,
|
path: urlObj.pathname,
|
||||||
query: new URL(url).search,
|
query: urlObj.search,
|
||||||
headerNames: Object.keys(headers),
|
headerNames: Object.keys(headers),
|
||||||
headers: headersWithoutSensitive,
|
headers: headersWithoutSensitive,
|
||||||
bodyShape,
|
bodyShape,
|
||||||
timestamp: new Date().toISOString(),
|
timestamp: new Date().toISOString(),
|
||||||
});
|
});
|
||||||
|
} catch (err) {
|
||||||
|
// Never throw from debug tooling; keep best-effort logging
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.warn('[DEBUG] debugRequest failed to parse URL or body', { url, error: err });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
39
susconecta/pages/api/signin-user.ts
Normal file
39
susconecta/pages/api/signin-user.ts
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||||
|
import { ENV_CONFIG } from '@/lib/env-config';
|
||||||
|
|
||||||
|
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||||
|
if (req.method !== 'POST') {
|
||||||
|
res.setHeader('Allow', 'POST');
|
||||||
|
return res.status(405).json({ error: 'Method not allowed' });
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const payload = req.body;
|
||||||
|
|
||||||
|
// Lightweight debug log to confirm the pages API route is invoked.
|
||||||
|
try {
|
||||||
|
console.log('[pages/api/signin-user] POST received', { url: req.url, email: payload?.email ?? null });
|
||||||
|
} catch (e) {
|
||||||
|
// ignore logging errors
|
||||||
|
}
|
||||||
|
const url = `${ENV_CONFIG.SUPABASE_URL}/auth/v1/signin`;
|
||||||
|
|
||||||
|
const response = await fetch(url, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
apikey: ENV_CONFIG.SUPABASE_ANON_KEY,
|
||||||
|
},
|
||||||
|
body: JSON.stringify(payload),
|
||||||
|
});
|
||||||
|
|
||||||
|
const text = await response.text();
|
||||||
|
let data: any = null;
|
||||||
|
try { data = text ? JSON.parse(text) : null; } catch { data = text; }
|
||||||
|
|
||||||
|
return res.status(response.status).json(data);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('[pages/api/signin-user] Unexpected error', error);
|
||||||
|
return res.status(500).json({ error: 'Internal proxy error' });
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user