# Wire your auth provider You've seen identify(). This is exactly where it goes for your auth provider — Firebase, Supabase, Auth0, Clerk, NextAuth — and the one timing rule that makes it reliable. Source: https://cross-deck.com/university/wire-your-auth-provider/ Verified Crossdeck University lesson — prose plus real, runnable code. ## "Who is signed in" depends entirely on your provider The SDK auto-captures sessions, page views, clicks, and errors the moment you call init() — but every event is attached to an anonymous device ID. To turn that anonymous timeline into a named user, you call Crossdeck.identify(userId) with the same stable ID your auth provider already gives you. Why isn't this automatic? Because "who is signed in" isn't knowable from inside a generic browser SDK — the shape of "the current user" depends on which provider you wired. Firebase exposes auth.currentUser.uid; Supabase exposes session.user.id; Auth0 exposes user.sub; Clerk exposes user.id. So you point Crossdeck at the right one. It's one line per provider. ## Identify on sign-in, reset on sign-out Find your provider, drop this into your auth state listener, and you're done. The pattern is always the same: identify(userId) when a user is present, reset() when they sign out. ```web import { onAuthStateChanged } from "firebase/auth"; onAuthStateChanged(auth, (user) => { if (user) Crossdeck.identify(user.uid); else Crossdeck.reset(); }); ``` ```supabase supabase.auth.onAuthStateChange((_event, session) => { if (session?.user) Crossdeck.identify(session.user.id); else Crossdeck.reset(); }); ``` ```clerk // useUser() — same async hydration; wait for isLoaded const { isLoaded, isSignedIn, user } = useUser(); useEffect(() => { if (!isLoaded) return; if (isSignedIn && user) Crossdeck.identify(user.id); else Crossdeck.reset(); }, [isLoaded, isSignedIn, user]); ``` ```nextauth // useSession() — status gates the call const { data: session, status } = useSession(); useEffect(() => { if (status === "authenticated") Crossdeck.identify(session.user.id); else if (status === "unauthenticated") Crossdeck.reset(); }, [status, session]); ``` ## The one timing rule — and what the alias preserves The rule that makes every one of these reliable: call identify() when the user resolves, not at init(). Auth providers hydrate asynchronously — Firebase's onAuthStateChanged can fire 50–800ms after init; Auth0's user is undefined during the redirect handoff; Clerk and NextAuth gate on a loaded/status flag. That's exactly why the call lives inside the listener or effect: it runs the moment the real user ID exists, never against a half-loaded null. And here's what you get for free: the alias preserves the anonymous timeline. When you call identify(), Crossdeck doesn't start a fresh person — it aliases the anonymous device ID into your user, so everything that happened before sign-up stays attached to them. Your sign-up funnel survives, because the visitor who browsed pricing and the user who converted are one record, not two. ## Signed-in users, by name — history intact Sign in. Within a moment the People page shows that user by their real ID, with the pre-signup events still on their timeline. Sign out and the next session is anonymous again — clean, no leakage between accounts on a shared device. identified · timeline intact user_847 on the People page — named, with the pricing-page visit from before they signed up still attached. One person, whole story.