Auth

AuthService

Servizio di autenticazione completo. Login, logout, register, activate, forgotPassword, resetPassword, refresh con locking concorrente. Implementa anche IAuthHandler per retry automatico su 401.

Cosa fa

AuthService e il servizio applicativo che orchestra tutte le operazioni di autenticazione contro un backend REST. Implementa contemporaneamente:

  • IAuthService — operazioni di dominio (login, logout, register, ecc.)
  • IAuthHandler — intercettore di errori 401 per il client HTTP, con refresh token automatico

Delega la persistenza dei token a un IAuthStrategy iniettato, restando agnostico dal meccanismo di storage.

Costruttore

class AuthService implements IAuthService, IAuthHandler {
  constructor(
    httpClient: IHttpClient,
    authStrategy: IAuthStrategy,
    logger?: ILogger
  )
}
ParametroTipoDefaultDescrizione
httpClientIHttpClientClient HTTP per le request /auth/*
authStrategyIAuthStrategyStrategia per la persistenza di token e refresh token
loggerILoggernew ConsoleLogger()Logger per errori/warning
In genere si crea l'istanza via AuthServiceFactory.create(...) per uniformare lo stile factory del package.

Endpoint utilizzati

Tutti gli endpoint sono convention-based e devono essere esposti dal backend con il prefisso assoluto/relativo configurato sul client HTTP:

MetodoURLBody
loginPOST /auth/loginUserCredentials
logoutPOST /auth/logout{ refreshToken }
registerPOST /auth/registerRegisterUser
activateAccountGET /auth/activate-account?token=...
forgotPasswordPOST /auth/forgot-passwordForgotPassword
resetPasswordPOST /auth/reset-passwordResetPassword
refreshTokenPOST /auth/refresh-token{ refreshToken }

Metodi principali

login(credentials): Promise<AuthResponse | null>

Effettua il login. In caso di successo i token vengono salvati automaticamente tramite la strategy. Ritorna null in caso di errore (consulta getLastError() per dettagli).

const result = await authService.login({
  email: 'user@example.com',
  password: 'password123',
})

if (!result) {
  const err = authService.getLastError()
  console.error(`[${err?.code}] ${err?.message}`)
}

logout(refreshToken: string | null): Promise<void>

Logout fail-safe: pulisce prima lo stato locale (token + cache invalidate), poi notifica il server con timeout di 5 secondi. Se la chiamata server fallisce, lo stato locale rimane pulito e l'errore e registrato in lastError.

await authService.logout(null) // usa il refreshToken corrente

refreshToken(token?, refreshToken?): Promise<AuthResponse | null>

Aggiorna i token. Implementa locking concorrente: se un refresh e gia in corso, le chiamate successive attendono il completamento del primo (evita refresh duplicati e race condition). Le richieste in attesa vengono notificate dopo 200ms dal nuovo token.

handleAuthError(error: AxiosError): Promise<boolean>

Hook IAuthHandler chiamato dal client HTTP su risposta 401. Tenta il refresh e ritorna true se la richiesta originale puo essere ritentata.

httpClient.setAuthHandler(authService)
// Ogni risposta 401 attiva refresh + retry automatico
const data = await httpClient.get('/api/protected')

Altri metodi

  • register(user) — registra un nuovo utente, ritorna CustomResponse
  • activateAccount(token) — attiva account via token email
  • forgotPassword({ email }) — invia email di reset (risposta generica per evitare enumeration)
  • resetPassword({ token, password }) — reimposta la password
  • getToken() / getRefreshToken() — accessor diretti via strategy
  • setTokens(token, refreshToken) — set manuale dei token (passare null, null per logout locale)
  • getLastError() — ultimo errore con code, message, timestamp, details

Codici errore

Tutti gli errori vengono normalizzati in AuthError con codici:

  • AUTH_INVALID_RESPONSE — risposta server non conforme allo schema
  • AUTH_ERROR_<status> — errore HTTP con status code (es. AUTH_ERROR_401)
  • AUTH_REFRESH_MISSING_TOKEN — manca il refresh token
  • AUTH_REFRESH_INVALID_RESPONSE — refresh response non valida
  • AUTH_REFRESH_FAILED — refresh fallito (network/server)
  • AUTH_LOGOUT_SERVER_FAILED — logout server fallito (stato locale gia pulito)
  • AUTH_UNKNOWN_ERROR — errore imprevisto

Factory

Per creare istanze in modo consistente con il resto del package, vedi AuthServiceFactory.

Esempio integrato

import {
  HttpClientFactory,
  AuthStrategyFactory,
  AuthServiceFactory,
} from '@pzeta/postgrest'

const httpClient = HttpClientFactory.createFetchClient({ baseURL: '/api' })
const strategy = AuthStrategyFactory.createJwtStrategy()
const authService = AuthServiceFactory.create(httpClient, strategy)

httpClient.setAuthStrategy(strategy)
httpClient.setAuthHandler(authService)

if (!strategy.isAuthenticated()) {
  await authService.login({ email, password })
}

Vedi anche