Claude/wonderful davinci d rqvy#69
Conversation
inspectOidcStorage proved the refresh token loss is a library-side resetAuthDataInStore() (blob survives, authnResult emptied), not iOS eviction. The reset is triggered by a failing silent renew - which runs independently of AuthService.refresh() and was therefore unlogged. Subscribe to PublicEventsService as an app initializer (registered before withAppInitializerAuthCheck so it catches the bootstrap renew) and log the renew lifecycle: validation result and the Azure error/error_description (AADSTS code) behind a failure. Structure only, no token values. https://claude.ai/code/session_01FncAPUn5nj7aeECLoa1bnD
Throw out angular-auth-oidc-client (too much hidden behavior: any failed refresh silently wiped the stored session and stopped the background renew timer, plus an uncontrolled timer-based renew loop). Move to oidc-client-ts driven through UserManager with every automatic behavior disabled (automaticSilentRenew/monitorSession/loadUserInfo off), so every redirect, token exchange, refresh and storage write is our own explicit, logged code. - auth.config.ts: build a single UserManager from the runtime EnvironmentConfig (Azure AD vs mock branch unchanged); keep user + PKCE state in localStorage so they survive the iOS PWA redirect. - auth.service.ts: same public surface (isAuthenticated, userData, init, login, logout, ensureAuthenticated, refresh) backed by UserManager; a failed signinSilent no longer wipes the session. Port the storage introspection and structured [auth] logging to the new user-blob shape. - token.interceptor.ts: attach the bearer token ourselves (replaces the library's authInterceptor); authRetryInterceptor 401 recovery unchanged. - user-profile.service.ts: read id_token claims from the new userData shape. - faro.ts: explicit flushFaro() before redirects to keep pre-redirect logs. Client builds clean; E2E mock-OIDC contract (authority, scopes, /api bearer) is unchanged so the Playwright suite needs no changes. https://claude.ai/code/session_01FncAPUn5nj7aeECLoa1bnD
Code ReviewOverviewThis PR migrates the Angular client from Code Quality & StylePositive
Issues
Potential Bugs
Security Considerations
Test CoverageNo new tests are included. This is a significant auth library migration that changes:
The existing Playwright E2E tests presumably cover the login/logout happy path, but they would not catch regressions in the cold-start refresh, foreground-refresh, or 401-retry paths. Consider adding (or noting that you've manually verified) coverage for:
SummaryThe migration is architecturally cleaner than the old library integration. The explicit control over every automatic behaviour, the clear separation into single-responsibility helpers, and the improved signal-based state are all improvements. The main things to address before merging:
|
…imer Keep Faro's default 250ms batching (drop the sendTimeout:0 override). Faro 2.x has no public flush, so wrap each transport's send to track the network promise it returns, and make flushFaro() push a marker, let the batch interval dispatch the buffered logs, then await every tracked send (bounded by a timeout so a redirect never hangs). login()/logout() now await flushFaro() before signinRedirect/signoutRedirect. https://claude.ai/code/session_01FncAPUn5nj7aeECLoa1bnD
Code ReviewOverviewThis PR migrates the Angular client's OIDC authentication from What's Good
Issues1. Dead injection —
|
Per the Angular style guide (signals/resources, not rxjs where possible), make AuthService signal-first and Observable-free: - state stays in signals (user, isAuthenticated, userData) - ensureAuthenticated() and refresh() return Promises (CanActivateFn accepts a Promise<boolean>); single-flight refresh is a tracked Promise instead of a shareReplay Observable - proactive foreground refresh uses addEventListener + a timestamp throttle (cleaned up via DestroyRef.onDestroy) instead of merge/fromEvent/throttleTime resource() isn't a fit here: refresh is event-driven and imperative (the guard branches into a redirect side-effect), so signals + async/await is the idiomatic non-rxjs model. authRetryInterceptor (an HttpInterceptorFn, which must return an Observable) now wraps the refresh Promise with from(). https://claude.ai/code/session_01FncAPUn5nj7aeECLoa1bnD
Code ReviewOverviewThis PR migrates the Angular frontend authentication from What Works Well
Issues
|
No description provided.