98 lines
3.0 KiB
TypeScript
98 lines
3.0 KiB
TypeScript
interface AuthUser {
|
|
nome: string
|
|
email: string
|
|
papel: string
|
|
}
|
|
|
|
export interface TenantOption {
|
|
id: string
|
|
name: string
|
|
slug: string
|
|
}
|
|
|
|
export type LoginResult =
|
|
| { success: true }
|
|
| { success: false; error: string }
|
|
| { needsTenantSelect: true; tenants: TenantOption[]; email: string; password: string }
|
|
|
|
export function useAuth() {
|
|
const { public: { apiBase } } = useRuntimeConfig()
|
|
|
|
const user = useState<AuthUser | null>('auth_user', () => null)
|
|
const token = useCookie<string | null>('auth_token', { maxAge: 60 * 60 * 8 })
|
|
const refreshToken = useCookie<string | null>('refresh_token', { maxAge: 60 * 60 * 24 * 7 })
|
|
|
|
const isAuthenticated = computed(() => !!token.value)
|
|
|
|
// Restaura usuário do token ao recarregar
|
|
if (token.value && !user.value) {
|
|
try {
|
|
const payload = JSON.parse(atob(token.value.split('.')[1]))
|
|
user.value = { nome: payload.email.split('@')[0], email: payload.email, papel: payload.role }
|
|
} catch {
|
|
token.value = null
|
|
}
|
|
}
|
|
|
|
function _applyTokens(access: string, refresh: string) {
|
|
token.value = access
|
|
refreshToken.value = refresh
|
|
const payload = JSON.parse(atob(access.split('.')[1]))
|
|
user.value = { nome: payload.email.split('@')[0], email: payload.email, papel: payload.role }
|
|
}
|
|
|
|
async function login(email: string, password: string): Promise<LoginResult> {
|
|
try {
|
|
const res = await $fetch<{
|
|
tokens?: { access_token: string; refresh_token: string }
|
|
tenants?: TenantOption[]
|
|
}>(`${apiBase}/auth/login`, {
|
|
method: 'POST',
|
|
body: { email, password },
|
|
})
|
|
|
|
if (res.tokens) {
|
|
_applyTokens(res.tokens.access_token, res.tokens.refresh_token)
|
|
return { success: true }
|
|
}
|
|
|
|
if (res.tenants && res.tenants.length > 0) {
|
|
return { needsTenantSelect: true, tenants: res.tenants, email, password }
|
|
}
|
|
|
|
return { success: false, error: 'Resposta inesperada do servidor.' }
|
|
} catch (err: any) {
|
|
return { success: false, error: err?.data?.error || 'E-mail ou senha incorretos.' }
|
|
}
|
|
}
|
|
|
|
async function selectTenant(email: string, password: string, tenantId: string): Promise<{ success: boolean; error?: string }> {
|
|
try {
|
|
const res = await $fetch<{ access_token: string; refresh_token: string }>(`${apiBase}/auth/login/select-tenant`, {
|
|
method: 'POST',
|
|
body: { email, password, tenant_id: tenantId },
|
|
})
|
|
_applyTokens(res.access_token, res.refresh_token)
|
|
return { success: true }
|
|
} catch (err: any) {
|
|
return { success: false, error: err?.data?.error || 'Erro ao selecionar empresa.' }
|
|
}
|
|
}
|
|
|
|
function logout() {
|
|
// Fire-and-forget logout no back (invalida refresh token)
|
|
if (refreshToken.value) {
|
|
$fetch(`${apiBase}/auth/logout`, {
|
|
method: 'POST',
|
|
body: { refresh_token: refreshToken.value },
|
|
}).catch(() => {})
|
|
}
|
|
token.value = null
|
|
refreshToken.value = null
|
|
user.value = null
|
|
navigateTo('/login')
|
|
}
|
|
|
|
return { user, isAuthenticated, login, selectTenant, logout }
|
|
}
|