import type { TokenProvider } from './auth.ts'; import type { FetchLike } from './transport.ts'; /** Almacén mínimo compatible con `sessionStorage`/`localStorage`. */ export interface KeyValueStorage { getItem(key: string): string | null; setItem(key: string, value: string): void; removeItem(key: string): void; } export interface AuthorizationCodeOptions { /** Origen de la API, por ejemplo `https://datacenterv2.joyeriazafirox.com`. */ readonly apiUrl: string; readonly clientId: string; /** Debe coincidir exactamente con una `redirect_uri` registrada para el cliente. */ readonly redirectUri: string; /** Scopes separados por espacio; sólo los concedidos al cliente. */ readonly scope: string; /** * Sólo para clientes confidenciales que canjean el code en su servidor. * NUNCA lo incluyas en código que llegue a un navegador. */ readonly clientSecret?: string; /** Por defecto `sessionStorage` en el navegador o memoria en Node. */ readonly storage?: KeyValueStorage; /** Prefijo de las claves guardadas. Por defecto `zafirox.oauth.`. */ readonly storageKey?: string; readonly fetch?: FetchLike; readonly timeoutMs?: number; /** Segundos antes de `expires_in` en los que se renueva el access token. Por defecto 30. */ readonly refreshSkewSeconds?: number; readonly now?: () => number; /** Fuente de aleatoriedad para `code_verifier` y `state`. Por defecto Web Crypto. */ readonly randomBytes?: (length: number) => Uint8Array; /** SHA-256 para el `code_challenge`. Por defecto `crypto.subtle`. */ readonly sha256?: (input: string) => Promise; } export interface AuthorizationUrlOptions { /** Valor opaco anti-CSRF; si se omite se genera uno aleatorio. Vuelve intacto en el callback. */ readonly state?: string; /** Sugerencia de cuenta (cédula o correo) para precargar la pantalla de acceso. */ readonly loginHint?: string; /** `select_account` fuerza el selector de cuentas; `login` fuerza volver a escribir la contraseña. */ readonly prompt?: 'select_account' | 'login'; } export interface AuthorizationCodeSession { readonly scope: string; /** Milisegundos desde época en los que el access token deja de servir. */ readonly expiresAt: number; readonly hasRefreshToken: boolean; } export interface AuthorizationCodeProvider extends TokenProvider { /** Genera `code_verifier` y `state`, los guarda y devuelve la URL de «Acceder con Zafirox». */ createAuthorizationUrl(options?: AuthorizationUrlOptions): Promise; /** Sólo navegador: genera la URL y redirige la ventana actual. */ login(options?: AuthorizationUrlOptions): Promise; /** Procesa la URL de retorno (`code`+`state` o `error`), canjea el code con PKCE y guarda la sesión. */ completeLogin(callbackUrl: string | URL): Promise; /** `true` cuando hay una sesión guardada (aunque el access token esté por renovarse). */ isAuthenticated(): boolean; session(): AuthorizationCodeSession | null; /** Olvida la sesión y cualquier autorización pendiente en este almacén. */ logout(): void; } export interface PkcePair { readonly verifier: string; readonly challenge: string; } export declare const CLIENT_API_AUTHORIZE_PATH = "/api/v1/client/oauth/authorize"; export declare const CLIENT_API_TOKEN_PATH = "/api/v1/client/oauth/token"; export declare function base64UrlEncode(bytes: Uint8Array): string; /** * Par PKCE (RFC 7636 §4): verifier de 43 caracteres y challenge S256 en base64url. */ export declare function generatePkce(randomBytes?: (length: number) => Uint8Array, sha256?: (input: string) => Promise): Promise; /** * «Acceder con Zafirox»: OAuth 2.0 Authorization Code + PKCE (RFC 7636). * * La persona inicia sesión con su propia cuenta Zafirox en * `accounts.joyeriazafirox.com`; la aplicación nunca ve su contraseña. Flujo: * * 1. `login()` (o `createAuthorizationUrl()`) envía al navegador a * `GET /api/v1/client/oauth/authorize`, que redirige a la pantalla de cuentas. * 2. Tras el consentimiento, el navegador vuelve a `redirectUri` con `code` y `state`. * 3. `completeLogin(location.href)` canjea el code con el `code_verifier` guardado y * persiste access + refresh token en el almacén. * 4. `getAccessToken()` renueva en silencio con el refresh token (rotación) cuando el * access token expira; si la renovación es rechazada, la sesión se borra y hay que * volver a `login()`. * * Un cliente público (SPA, móvil) no lleva `clientSecret`; un backend confidencial que * canjee el code en servidor puede pasarlo y se autentica con HTTP Basic. */ export declare function createAuthorizationCodeProvider(options: AuthorizationCodeOptions): AuthorizationCodeProvider; //# sourceMappingURL=authorization-code.d.ts.map