Skip to content
Back

Simplest Appwrite + Riverpod + Go_router auth flow

  • 0
  • Flutter
  • Auth
  • Cloud
standa 🧃
6 Aug, 2025, 12:51

Hey, I managed to get native Google Sign-In working with Appwrite custom tokens and Riverpod/GoRouter, and I’m stuck on three things:


1) SDK user identification/reset without authStateChanges Stream

I need to call sdkIdentificationService.identifyUser(userId) (e.g. RevenueCat, OneSignal, Sentry, PostHog) when the user signs in or out, and also after app startup to pick up an existing session.

  • When should I run identify/reset?
    • On app startup
    • On manual login/logout
      • which idk if should be called when deleting user or not (question 3)
  • Do I need to hook into some other events, or will Appwrite handle that under the hood? (might be tied to 3rd question)

2) Routing without authStateChanges stream

Previously I used a refreshListenable to rebuild GoRouter and in its redirect I got user synchronously final isLoggedIn = authRepository.currentUser != null;. Now, since it's not possible with appwrite's sdk, I came up (or AI did) with something like this:

TypeScript
@riverpod
class AuthState extends _$AuthState {
  FutureOr<User?> build() => ref.read(authRepo).getCurrentUser();

  Future<void> signIn() async {
    state = const AsyncValue.loading();
    await ref.read(authRepo).signInWithGoogle();
    final user = await ref.read(authRepo).getCurrentUser();
    state = AsyncValue.data(user);
    unawaited(sdkIdentificationService.identifyUser(user!.$id));
  }

  Future<void> signOut() async {
    await ref.read(authRepo).signOut();
    state = const AsyncValue.data(null);
    unawaited(sdkIdentificationService.resetUser());
  }
}

@riverpod
GoRouter router(Ref ref) {
  final auth    = ref.watch(authStateProvider);
  final onboard = ref.watch(onboardingProvider);
  final premium = ref.watch(premiumProvider);

  return GoRouter(
    initialLocation: '/loading',
    redirect: (ctx, state) {
      if (auth.isLoading) return '/loading';
      final loggedIn = auth.value != null;
      // Onboarding âž” Paywall âž” Login âž” Home
      // ...
      return null;
    },
    routes: [ /* … */ ],
  );
}

I’ve heard rebuilding/disposing the router on every auth change is very bad practice.

What’s the recommended pattern for conditional redirects (Onboarding → Paywall → Login → Home) without an authStateChanges stream or a synchronous user provider, since appwrite sdk doesn't provide them?


3) Deleting a user

When I call my server function to delete a user, do I need to explicitly delete their Appwrite session afterward on client, or does the SDK automatically invalidate it? Should my redirect logic account for this somehow?

TL;DR
1) Identify/reset users on app startup and manual login/logout. Appwrite should handle events under the hood. 2) Use conditional redirects in GoRouter without authStateChanges stream by managing state changes in Riverpod. 3) Delete a user on the server, the Appwrite SDK should automatically invalidate their session. No need to explicitly delete the session on the client.
Reply

Reply to this thread by joining our Discord

Reply on Discord

Need support?

Join our Discord

Get community support by joining our Discord server.

Join Discord

Get premium support

Join Appwrite Pro and get email support from our team.

Learn more