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
- An existing Archipelago monorepo (see Monorepo Scaffolding)
- For the
rest_apibackend, a network SDK (see Network SDK Setup)
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:
archipelago generate auth_sdkThe main variables are:
- authBackend:
rest_api(default),supabaseorfirebase - stateManagement:
bloc,cubit,riverpodorprovider - 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:
{
"authBackend": "rest_api",
"stateManagement": "bloc",
"includeAnonymousAuth": false,
"includePhoneOtp": false
}archipelago generate auth_sdk --config auth_config.jsonAn 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.
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:
dependencies:
auth_api:
path: ../../auth/auth_apiStep 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:
final authGuard = AuthGuard(GetIt.I<AuthSDK>());
registry.register([
AutoRoute(page: HomeRoute.page, path: '/home', guards: [authGuard]),
]);Listen to status and lifecycle events:
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_apicallsPOST /auth/login,/auth/registerand/auth/refreshthrough theHttpClientport. It works with the Dio or http network SDK. Point the datasource at your backend and change the model parsing to match your API.supabaseusessupabase_flutter. The Supabase client refreshes tokens.firebaseusesfirebase_auth. Refresh callsgetIdToken(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 registersSupabaseAuthInitializeras a pre-launch step and addsSUPABASE_URLandSUPABASE_ANON_KEYtoshared/app_config. Replace the placeholders in each.env.<flavor>with your project's URL and anon key, then runmelos run env:switch -- developmentandmelos run build.firebase: it addsFirebase.initializeApp()tobootstrap.dart, also in a project generated without Firebase. Runflutterfire configurein 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
await getIt<AuthSDK>().deleteAccount(); // always generated
await getIt<AuthSDK>().signInAnonymously(); // includeAnonymousAuth
final handle = await getIt<AuthSDK>().requestPhoneOtp('+6281234567890'); // includePhoneOtpdeleteAccount 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
cd features/auth/auth_impl
flutter testtest/src/di/auth_di_test.dart checks the container isolation, imports and teardown.
Common Customizations
| Customization | Where to Change |
|---|---|
| Token format | The token model in data/models/ |
| Endpoints | The remote datasource in data/datasources/ |
| Biometric re-login | Add biometric_auth_sdk |
| Social login | Add social_auth_sdk |
| Login and register UI | presentation/login/ and presentation/register/ |
| Translations | l10n/auth_en.i18n.json and auth_id.i18n.json |
Next Steps
- Set up the UI Kit to theme your login pages
- Configure monitoring to track auth failures