guisilvagomes eae5e8cb92 Atualizar
2025-10-24 12:03:40 -03:00

336 lines
8.4 KiB
TypeScript

/**
* Serviço de Autenticação (Frontend)
* Chama Supabase diretamente
*/
import axios from "axios";
import { API_CONFIG } from "../api/config";
import type {
LoginInput,
LoginResponse,
AuthUser,
RefreshTokenResponse,
} from "./types";
class AuthService {
/**
* Faz login com email e senha
*/
async login(credentials: LoginInput): Promise<LoginResponse> {
try {
console.log("[authService] Tentando login com:", credentials.email);
const response = await axios.post<LoginResponse>(
`${API_CONFIG.AUTH_URL}/token?grant_type=password`,
{
email: credentials.email,
password: credentials.password,
},
{
headers: {
"Content-Type": "application/json",
apikey: API_CONFIG.SUPABASE_ANON_KEY,
},
}
);
console.log("[authService] Login bem-sucedido:", response.data);
// Salva tokens e user no localStorage
if (response.data.access_token) {
localStorage.setItem(
API_CONFIG.STORAGE_KEYS.ACCESS_TOKEN,
response.data.access_token
);
localStorage.setItem(
API_CONFIG.STORAGE_KEYS.REFRESH_TOKEN,
response.data.refresh_token
);
localStorage.setItem(
API_CONFIG.STORAGE_KEYS.USER,
JSON.stringify(response.data.user)
);
}
return response.data;
} catch (error: any) {
console.error("[authService] Erro no login:", error);
console.error("[authService] Response data:", error.response?.data);
console.error("[authService] Response status:", error.response?.status);
throw error;
}
}
/**
* Registro público (signup) com email e senha
* POST /auth/v1/signup
* Não requer autenticação - permite auto-registro
*/
async signup(data: {
email: string;
password: string;
full_name: string;
phone?: string;
}): Promise<LoginResponse> {
try {
const response = await axios.post<LoginResponse>(
`${API_CONFIG.AUTH_URL}/signup`,
{
email: data.email,
password: data.password,
options: {
data: {
full_name: data.full_name,
phone: data.phone,
},
},
},
{
headers: {
"Content-Type": "application/json",
apikey: API_CONFIG.SUPABASE_ANON_KEY,
},
}
);
// Salva tokens e user no localStorage
if (response.data.access_token) {
localStorage.setItem(
API_CONFIG.STORAGE_KEYS.ACCESS_TOKEN,
response.data.access_token
);
localStorage.setItem(
API_CONFIG.STORAGE_KEYS.REFRESH_TOKEN,
response.data.refresh_token
);
localStorage.setItem(
API_CONFIG.STORAGE_KEYS.USER,
JSON.stringify(response.data.user)
);
}
return response.data;
} catch (error) {
console.error("Erro no signup:", error);
throw error;
}
}
/**
* Envia magic link para o email do usuário
* POST /auth/v1/otp
*/
async sendMagicLink(
email: string,
redirectUrl?: string
): Promise<{ success: boolean; message: string }> {
try {
await axios.post(
`${API_CONFIG.AUTH_URL}/otp`,
{
email,
options: {
emailRedirectTo:
redirectUrl || `${API_CONFIG.APP_URL}/auth/callback`,
},
},
{
headers: {
"Content-Type": "application/json",
apikey: API_CONFIG.SUPABASE_ANON_KEY,
},
}
);
return {
success: true,
message: "Magic link enviado com sucesso",
};
} catch (error) {
console.error("Erro ao enviar magic link:", error);
throw error;
}
}
/**
* Solicita reset de senha via email (público)
* POST /auth/v1/recover
*/
async requestPasswordReset(
email: string,
redirectUrl?: string
): Promise<{ success: boolean; message: string }> {
try {
await axios.post(
`${API_CONFIG.AUTH_URL}/recover`,
{
email,
options: {
redirectTo: redirectUrl || `${API_CONFIG.APP_URL}/reset-password`,
},
},
{
headers: {
"Content-Type": "application/json",
apikey: API_CONFIG.SUPABASE_ANON_KEY,
},
}
);
return {
success: true,
message:
"Email de recuperação de senha enviado com sucesso. Verifique sua caixa de entrada.",
};
} catch (error) {
console.error("Erro ao solicitar reset de senha:", error);
throw error;
}
}
/**
* Atualiza a senha do usuário usando o token de recuperação
* PUT /auth/v1/user
*/
async updatePassword(
accessToken: string,
newPassword: string
): Promise<{ success: boolean; message: string }> {
try {
await axios.put(
`${API_CONFIG.AUTH_URL}/user`,
{
password: newPassword,
},
{
headers: {
"Content-Type": "application/json",
apikey: API_CONFIG.SUPABASE_ANON_KEY,
Authorization: `Bearer ${accessToken}`,
},
}
);
return {
success: true,
message: "Senha atualizada com sucesso",
};
} catch (error) {
console.error("Erro ao atualizar senha:", error);
throw error;
}
}
/**
* Faz logout (invalida sessão no servidor e limpa localStorage)
*/
async logout(): Promise<void> {
try {
const token = localStorage.getItem(API_CONFIG.STORAGE_KEYS.ACCESS_TOKEN);
if (token) {
// Chama API para invalidar sessão no servidor
await axios.post(
`${API_CONFIG.AUTH_URL}/logout`,
{},
{
headers: {
"Content-Type": "application/json",
apikey: API_CONFIG.SUPABASE_ANON_KEY,
Authorization: `Bearer ${token}`,
},
}
);
}
} catch (error) {
console.error("Erro ao invalidar sessão no servidor:", error);
// Continua mesmo com erro, para garantir limpeza local
} finally {
// Sempre limpa o localStorage
localStorage.removeItem(API_CONFIG.STORAGE_KEYS.ACCESS_TOKEN);
localStorage.removeItem(API_CONFIG.STORAGE_KEYS.REFRESH_TOKEN);
localStorage.removeItem(API_CONFIG.STORAGE_KEYS.USER);
}
}
/**
* Verifica se usuário está autenticado
*/
isAuthenticated(): boolean {
return !!localStorage.getItem(API_CONFIG.STORAGE_KEYS.ACCESS_TOKEN);
}
/**
* Retorna o usuário atual do localStorage
*/
getCurrentUser(): AuthUser | null {
const userStr = localStorage.getItem(API_CONFIG.STORAGE_KEYS.USER);
if (!userStr) return null;
try {
return JSON.parse(userStr);
} catch {
return null;
}
}
/**
* Retorna o access token
*/
getAccessToken(): string | null {
return localStorage.getItem(API_CONFIG.STORAGE_KEYS.ACCESS_TOKEN);
}
/**
* Renova o access token usando o refresh token
*/
async refreshToken(): Promise<RefreshTokenResponse> {
try {
const refreshToken = localStorage.getItem(
API_CONFIG.STORAGE_KEYS.REFRESH_TOKEN
);
if (!refreshToken) {
throw new Error("Refresh token não encontrado");
}
const response = await axios.post<RefreshTokenResponse>(
`${API_CONFIG.AUTH_URL}/token?grant_type=refresh_token`,
{
refresh_token: refreshToken,
},
{
headers: {
"Content-Type": "application/json",
apikey: API_CONFIG.SUPABASE_ANON_KEY,
},
}
);
// Atualiza tokens e user no localStorage
if (response.data.access_token) {
localStorage.setItem(
API_CONFIG.STORAGE_KEYS.ACCESS_TOKEN,
response.data.access_token
);
localStorage.setItem(
API_CONFIG.STORAGE_KEYS.REFRESH_TOKEN,
response.data.refresh_token
);
localStorage.setItem(
API_CONFIG.STORAGE_KEYS.USER,
JSON.stringify(response.data.user)
);
}
return response.data;
} catch (error) {
console.error("Erro ao renovar token:", error);
// Se falhar, limpa tudo e força novo login
this.logout();
throw error;
}
}
}
export const authService = new AuthService();