import { HttpClient } from '@angular/common/http'; import { Router } from '@angular/router'; import { Observable } from 'rxjs'; import { AuthService } from './auth.service'; import { ValtechAuthConfig } from './types'; import * as i0 from "@angular/core"; /** * Name of the query param that carries the handoff token. Apps may override * via `detectAndExchangeHandoff({ tokenParam })` but the default keeps the * convention consistent across the factory. */ export declare const HANDOFF_TOKEN_PARAM = "handoff"; /** * Name of the query param that carries the post-exchange route. */ export declare const HANDOFF_ROUTE_PARAM = "route"; /** * Options for `HandoffService.detectAndExchangeHandoff`. */ export interface DetectAndExchangeOptions { /** Override the query param name. Default: `'handoff'`. */ tokenParam?: string; /** Override the route param name. Default: `'route'`. */ routeParam?: string; /** Where to navigate if no route param is present. Default: `'/'`. */ defaultRoute?: string; /** Where to navigate on exchange error. Default: app's configured `loginRoute`. */ errorRoute?: string; } /** * Request body for `POST /v2/auth/handoff`. * * Both fields are optional and stored for audit only — the exchange step * does not enforce that the redeeming app matches `targetAppId`. */ export interface HandoffCreateRequest { /** Target app the handoff is intended for (e.g. `"myvaltech"`). Audit-only. */ targetAppId?: string; /** Route the target app should navigate to after exchange. Echoed back. */ route?: string; } /** * Response body from `POST /v2/auth/handoff`. */ export interface HandoffCreateResponse { operationId: string; /** Raw token to embed in the redirect URL as `?handoff=`. 30s TTL, single-use. */ token: string; /** RFC3339 expiration timestamp. */ expiresAt: string; /** Echoed `route` from the request, when provided. */ route?: string; /** * Absolute base URL of the target app (e.g. `"https://sigify.com"`). * * When present, callers should use this as the destination for the redirect. * Backend resolves it from the `app-config` table (single source of truth). * * Optional for backward compatibility — when missing, callers may fall back * to a client-side `appUrls` mapping. */ targetBaseUrl?: string; } /** * Response body from `POST /v2/auth/handoff/exchange`. * * Same shape as `SigninResponse` — installable via `AuthService.setExternalAuth`. */ export interface HandoffExchangeResponse { operationId: string; accessToken: string; refreshToken: string; firebaseToken?: string; expiresIn: number; tokenType: string; userId: string; } /** * HandoffService — cross-app session transfer. * * Implements the OAuth Authorization Code pattern, applied internally between * apps that share the same backend. * * **Origin app (user is authenticated):** * * ```typescript * const { token, route } = await firstValueFrom( * handoff.createHandoff({ targetAppId: 'myvaltech', route: '/app/dashboard' }) * ); * window.location.href = `https://myvaltech.app/?handoff=${token}&route=${encodeURIComponent(route ?? '/')}`; * ``` * * **Target app (boot):** call `exchangeHandoff(token)`. On success, the session * is installed (`AuthService.setExternalAuth`) and the user is authenticated. * See `detectAndExchangeHandoff` helper for the typical bootstrap pattern. * * Security notes: * - Token is single-use and short-lived (30s) — enforced server-side. * - Token in URL must be removed from history after exchange to avoid log leakage. * - The exchange endpoint is public; do NOT add auth header. The * `HttpClient` request below avoids triggering the auth interceptor since the * user isn't logged in yet on the target app. */ export declare class HandoffService { private config; private http; private auth; private router; private detected; constructor(config: ValtechAuthConfig | null, http: HttpClient, auth: AuthService, router: Router); /** * Create a handoff token. Caller must be authenticated. * * @param request Optional metadata: target app id and intended route. * @returns Observable emitting `{ token, expiresAt, route? }`. */ createHandoff(request?: HandoffCreateRequest): Observable; /** * Exchange a handoff token for a session and install it. * * On success, the response is piped through `AuthService.setExternalAuth` * so the user becomes authenticated. Subsequent navigation can proceed. * * On failure, the observable errors. The caller is responsible for * showing an error and routing to `/login`. * * @param token Raw handoff token read from the URL. */ exchangeHandoff(token: string): Observable; /** * Bootstrap helper — reads the handoff token from the current URL, exchanges * it for a session, and navigates to the intended route with the token * stripped from history. * * Idempotent: subsequent calls are no-ops. Wire from an * `APP_INITIALIZER`/`provideAppInitializer` factory in `main.ts`. * * ```typescript * // main.ts * provideAppInitializer(() => inject(HandoffService).detectAndExchangeHandoff()) * ``` * * On error (expired/used/invalid token), redirects to `errorRoute` (default: * the app's configured `loginRoute`). The URL is always cleaned, even on * error, so the token cannot be retried by refreshing the page. * * @returns `true` if a handoff was detected and processed (success or fail). * `false` if no token was present (cold boot, normal flow). */ detectAndExchangeHandoff(options?: DetectAndExchangeOptions): Promise; /** * Persist the session in `AuthService`. Mirrors the install flow used by * the normal signin path so timers, Firebase, and tab-sync all kick in. */ private installSession; private get baseUrl(); static ɵfac: i0.ɵɵFactoryDeclaration; static ɵprov: i0.ɵɵInjectableDeclaration; }