# Tasks: enterprise-react-auth **Change ID**: enterprise-react-auth **Package**: `@suaveplan/react-auth` **Target path**: `react/auth/react-auth` **Prerequisite packages on Verdaccio**: `@suaveplan/error`, `@suaveplan/types`, `@suaveplan/events`, `@suaveplan/oauth-client`, `@suaveplan/react-translate` --- ## 1. Scaffold - [ ] Create directory tree per proposal layout. - [ ] Write `package.json` at `0.1.0` with `"sideEffects": false`, exports map. - [ ] Dependencies: `@suaveplan/error workspace:^`, `@suaveplan/types workspace:^`, `@suaveplan/events workspace:^`, `@suaveplan/oauth-client workspace:^`, `@suaveplan/react-translate workspace:^`, `zod catalog:forms`, `@opentelemetry/api catalog:observability`, `tslib catalog:build`. - [ ] Write `tsconfig.json`, `vitest.config.ts`, scripts. --- ## 2. Error codes and types - [ ] Define `AuthError` extending `SuaveplanError`; codes: `AUTH_UNAUTHENTICATED`, `AUTH_TOKEN_EXPIRED`, `AUTH_REFRESH_FAILED`, `AUTH_CONTEXT_MISSING`. - [ ] Define `AuthUser`, `AuthState`, `AuthConfig`, `AuthContextValue`, `AuthProviderProps`, `AuthGuardProps`, `SignInOptions`, `SignOutOptions`. - [ ] Write `AuthConfigSchema` Zod schema. --- ## 3. Token utilities - [ ] `src/utils/token-storage/` — `createTokenStorage(adapter: 'memory' | 'localStorage' | 'sessionStorage')`: `setTokens(tokens)`, `getTokens()`, `clearTokens()`. - [ ] `src/utils/session-persistence/` — `saveSession(user)`, `loadSession(): AuthUser | null`, `clearSession()`. - [ ] Write tests + md for each. --- ## 4. AuthContext + AuthProvider - [ ] State: `user: AuthUser | null`, `isLoading`, `isAuthenticated`. - [ ] `signIn(options: SignInOptions)` — calls `@suaveplan/oauth-client` authorization + token exchange; stores tokens; emits `@suaveplan/events` `auth:signed_in`. OTel `auth.sign_in` span. - [ ] `signOut(options?)` — clears tokens + session; emits `auth:signed_out`. OTel `auth.sign_out` span. - [ ] `refreshToken()` — calls `@suaveplan/oauth-client` token refresh; on failure throws `AuthError(AUTH_REFRESH_FAILED)`. OTel `auth.token_refresh` span. - [ ] Auto-refresh: installs a timer to refresh before expiry. - [ ] `useAuth()` throws `AuthError(AUTH_CONTEXT_MISSING)` outside provider. - [ ] Write `auth-context.test.tsx` (≤500 lines): sign-in, sign-out, refresh, auto-refresh timer, context missing. `{ timeout: 10000 }`. - [ ] Write `auth-context.md`. --- ## 5. Hooks - [ ] `useUser(): AuthUser | null` — from context. - [ ] `useIsAuthenticated(): boolean`. - [ ] `useAuthToken(): string | null` — current access token. - [ ] Write tests + md for each. --- ## 6. AuthGuard + withAuth - [ ] `AuthGuard` — renders children when authenticated; calls `onUnauthenticated` (default: throws `AuthError(AUTH_UNAUTHENTICATED)`) when not. - [ ] `withAuth(Component)` — HOC wrapping `AuthGuard`. - [ ] Write tests, stories (authenticated, unauthenticated-redirect, loading), md. --- ## 7. E2E - [ ] `e2e/auth.spec.ts` — Playwright with injected mock `@suaveplan/oauth-client`: - Render `AuthGuard` while unauthenticated → `onUnauthenticated` fires. - Call `signIn()` → user set in context → `AuthGuard` renders children. - Call `signOut()` → user cleared. --- ## 8. Verify and publish - [ ] `bunx turbo lint typecheck test --filter=@suaveplan/react-auth` — green. - [ ] `bunx turbo test:coverage --filter=@suaveplan/react-auth` — 100%. - [ ] `bun scripts/publish.ts --package @suaveplan/react-auth`. - [ ] Archive change folder.