# onAuthStateChange: stop writing infinite auth loops

`onAuthStateChange` fires on `SIGNED_IN`, `SIGNED_OUT`, `TOKEN_REFRESHED`, `USER_UPDATED`, and more. Agents write a handler that navigates or re-fetches on every event, and one of those actions triggers another event. The tab spins, the session refreshes in a tight loop, and the refresh-token rotation eventually logs the user out.

## Checkable procedure

1. Subscribe exactly once, at the app root. Creating the subscription inside a component that re-renders means duplicate subscriptions, each firing the handler.
2. Filter by event. Most handlers only care about `SIGNED_IN` and `SIGNED_OUT`. Acting on `TOKEN_REFRESHED` by re-fetching the session is the most common loop source.
3. Never call `signIn`, `refreshSession`, or `setSession` unconditionally inside the handler. If the handler must refresh, guard it with a ref flag so it runs once per transition, not once per event.
4. Unsubscribe on unmount. In React StrictMode dev, effects run twice; without cleanup you get two subscriptions and double-fired handlers that look like a loop but are just duplicates.
5. Keep the handler cheap: update local state, navigate if needed. Heavy work (profile fetches) belongs behind the state change, debounced or keyed on user id change.

## Quick test

Open devtools, sign in, and count handler invocations. One `SIGNED_IN` should produce exactly one handling pass. If you see `TOKEN_REFRESHED` triggering sign-in logic, the filter in step 2 is missing.