# Flutter + Supabase: the auth setup agents get wrong

Two steps, both required, and agents routinely do only the first: initialize the client, and register the deep link that brings the user back from the browser or email app. Skip the second and sign-in appears to succeed while the app never receives the session.

## Checkable procedure

1. Call `Supabase.initialize` once in `main()` with your project URL and publishable key, before `runApp`. Do not initialize in a widget; a second initialize races the first.
2. Pick your deep-link scheme and host (the docs use a scheme like `io.supabase.flutterquickstart` with host `login-callback`). Add the full redirect URL to the Redirect URLs list in the dashboard auth settings.
3. iOS: add `CFBundleURLTypes` with your scheme to `ios/Runner/Info.plist`. Android: add the intent filter with your scheme and host to the manifest. Without these the OS never routes the link back to your app.
4. Keep the default PKCE flow. In v2 it is the default for deep-link auth and more secure than implicit. Only switch to implicit if you have a concrete reason.
5. Listen with `onAuthStateChange` for the session event when the user returns via magic link. A new event fires on return; that is where you redirect into the app.
6. v2 timing trap: `Supabase.initialize()` returns as soon as the session is read from local storage, with no guarantee it is still valid. Check `session?.isExpired`, and if expired wait for the `tokenRefreshed` event instead of treating the user as signed out.

## Quick test

Send yourself a magic link, tap it on a real device, and confirm the app opens and signs in. If the email app opens the link in its own webview and nothing happens, the platform deep-link config in step 3 is missing.