Skip to content
Back to archipelago.banuacoder.com

Feature SDKs

How to add authentication to a Flutter app ​

Free Reference for auth_sdk: every variable, option and package it generates. Command: archipelago generate auth_sdk

Generate the Auth SDK with the backend you choose, gate routes with AuthGuard, listen to auth status and events, and see how token refresh and storage work.

What you'll learn ​

  • Generating the Auth SDK with the backend you choose
  • Understanding the generated packages and the eager SDK
  • Gating routes with AuthGuard
  • Listening to auth status and events
  • Seeing how token refresh and storage work

Prerequisites ​

For rest_api, the brick generates storage_sdk for you if it is missing. You do not install it first.

Step 1: Generate the Auth SDK ​

New projects can include auth through starterFeatures. To add it later, run:

bash
archipelago generate auth_sdk

The main variables are:

  • authBackend: rest_api (default), supabase or firebase
  • stateManagement: bloc, cubit, riverpod or provider
  • includeAnonymousAuth: guest sign-in (default false)
  • includePhoneOtp: phone OTP sign-in (default false)
  • isUsingMonitoring: report auth failures to AppMonitoring

The brick also reads appName, prefix and uiKitPackageName. Or use a config file:

json
{
  "authBackend": "rest_api",
  "stateManagement": "bloc",
  "includeAnonymousAuth": false,
  "includePhoneOtp": false
}
bash
archipelago generate auth_sdk --config auth_config.json

An off variable removes the whole capability. The AuthSDK interface then has no signInAnonymously or phone OTP method. No stub is generated.

Step 2: Understand the Generated Structure ​

Auth uses the API/Impl split because other features read auth state.

text
features/auth/
├── auth_api/
│   └── lib/src/
│       ├── auth_sdk.dart           # AuthSDK contract
│       ├── auth_status.dart
│       ├── auth_event.dart
│       └── enums/logout_reason.dart
└── auth_impl/
    ├── l10n/                       # Per-feature translations
    └── lib/src/
        ├── auth_sdk_impl.dart
        ├── data/                   # Datasources, models, repositories
        ├── di/                     # Global module, container, imports
        ├── domain/usecases/
        ├── presentation/           # Shell page, login and register pages
        └── router/

auth_api also holds the AuthGuard.

Step 3: Check the Registration ​

The post-generation hook registers AuthImplGlobalModule in the app injector. You write no registration code.

Auth is the one feature with an eager SDK. AuthSDKImpl restores the session before the first screen. Token refresh runs with no auth screen mounted. So AuthSDK, LoginRepository and the token store live in the root GetIt. The repository reaches AuthSDKImpl as a provider closure to avoid a DI cycle.

The login and register use cases live in authContainer, the feature container. auth_imports.dart forwards LoginRepository and AuthSDK into it. The shell page takes a lease and builds the state holders from it.

Other features depend on auth_api only:

yaml
dependencies:
  auth_api:
    path: ../../auth/auth_api

Step 4: Gate Routes and Listen to State ​

requireAuthentication() publishes state. It cannot navigate, so it cannot skip a guard. Attach AuthGuard to the routes you want protected:

dart
final authGuard = AuthGuard(GetIt.I<AuthSDK>());

registry.register([
  AutoRoute(page: HomeRoute.page, path: '/home', guards: [authGuard]),
]);

Listen to status and lifecycle events:

dart
final auth = getIt<AuthSDK>();

auth.statusStream.listen((status) {
  // react to AuthStatus changes
});

final remove = auth.addAuthEventListener((event) {
  // login, logout, token refresh failed
});

Step 5: Choose and Configure a Backend ​

  • rest_api calls POST /auth/login, /auth/register and /auth/refresh through the HttpClient port. It works with the Dio or http network SDK. Point the datasource at your backend and change the model parsing to match your API.
  • supabase uses supabase_flutter. The Supabase client refreshes tokens.
  • firebase uses firebase_auth. Refresh calls getIdToken(true).

Supabase and Firebase keep the session inside their own SDK. They generate no token store.

The vendor SDK must start before auth restores the session. The hook does this for you:

  • supabase: it registers SupabaseAuthInitializer as a pre-launch step and adds SUPABASE_URL and SUPABASE_ANON_KEY to shared/app_config. Replace the placeholders in each .env.<flavor> with your project's URL and anon key, then run melos run env:switch -- development and melos run build.
  • firebase: it adds Firebase.initializeApp() to bootstrap.dart, also in a project generated without Firebase. Run flutterfire configure in the app.

With archipelago create, pick the backend with the monorepo's authBackend option instead.

To change the backend later, run the brick again with the other authBackend. The hook removes the old backend's extras and lists anything you changed. See Switch the backend.

Step 6: Token Storage and Refresh ​

For rest_api, one class named SecureAuthTokenStore is the only writer of the token keys. It stores them through StorageProvider in a secure, user-scoped namespace. A logout clears them. It writes the refresh token first, so a crash mid-rotation is recoverable.

AuthImplGlobalModule registers an AuthTokenProvider for network_sdk_api. The HTTP client then attaches the bearer token and calls handleAuthenticationFailed on a 401. You write no interceptor. Install auth_sdk with a current network_sdk and refresh works.

Refresh is single-flight. A burst of parallel 401 responses joins one attempt. The login, register, refresh, anonymous and OTP endpoints are exempt from refresh, so a wrong password never starts a refresh.

Step 7: Account Deletion and Optional Flows ​

dart
await getIt<AuthSDK>().deleteAccount();   // always generated
await getIt<AuthSDK>().signInAnonymously(); // includeAnonymousAuth
final handle = await getIt<AuthSDK>().requestPhoneOtp('+6281234567890'); // includePhoneOtp

deleteAccount calls the backend, signs out locally and emits LogoutReason.accountDeleted. App stores require account deletion in apps that create accounts.

Step 8: Run the Tests ​

bash
cd features/auth/auth_impl
flutter test

test/src/di/auth_di_test.dart checks the container isolation, imports and teardown.

Common Customizations ​

CustomizationWhere to Change
Token formatThe token model in data/models/
EndpointsThe remote datasource in data/datasources/
Biometric re-loginAdd biometric_auth_sdk
Social loginAdd social_auth_sdk
Login and register UIpresentation/login/ and presentation/register/
Translationsl10n/auth_en.i18n.json and auth_id.i18n.json

Next Steps ​