token_storage
A Flutter wrapper around flutter_secure_storage
for managing an auth token pair and generic secure key-value storage,
with automatic cleanup on a fresh install.
Features
- Singleton
TokenStorage.i, initialized once withTokenStorage.init(). TokenPair(access token, optional refresh token —nullfor auth systems with no refresh mechanism — created/updated timestamps that default toDateTime.now()if omitted), persisted as a single secure-storage entry.saveToken/clearTokenfire a token listener (for driving navigation on login/logout);updateTokenpersists a silent refresh without firing it.TokenPair.isExpiredandTokenStorage.isTokenExpireddecode the access token as a JWT and check itsexpclaim, via the bundledJwtDecoder(no external JWT dependency).- Generic secure key-value storage:
put/getfor strings,putObject/getObjectfor JSON-serializable types,watchKey/unWatchKeyto react to changes on a given key. - Fresh-install cleanup: clears any secure data left over from a previous
install (iOS Keychain entries survive uninstall; this package detects
that with a
SharedPreferencesflag and clears secure storage once).
Usage
import 'package:token_storage/token_storage.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await TokenStorage.init();
runApp(const MyApp());
}
// Login
await TokenStorage.i.saveToken(
TokenPair(
accessToken: response.accessToken,
refreshToken: response.refreshToken,
// createdAt/updatedAt default to DateTime.now() if omitted.
),
);
// Read
final accessToken = await TokenStorage.i.accessToken;
// Check expiry (decodes the access token's JWT `exp` claim)
final expired = await TokenStorage.i.isTokenExpired; // null if no token stored
// Silent refresh (does not notify the token listener)
await TokenStorage.i.updateToken(refreshedPair);
// Logout
await TokenStorage.i.clearToken();
// React to login/logout
TokenStorage.i.setTokenListener((token) {
if (token == null) {
// navigate to login
}
});
// Generic secure storage
await TokenStorage.i.put('device_id', deviceId);
final deviceId = await TokenStorage.i.get('device_id');
await TokenStorage.i.putObject<Profile>('profile', profile, (p) => p.toJson());
final profile = await TokenStorage.i.getObject<Profile>('profile', Profile.fromJson);
// React to changes on a key (fires on put/putObject, and with null on
// remove/clearAll) — not fired for the token methods, which have their
// own listener via setTokenListener above.
void onThemeChanged(String? value) { /* ... */ }
TokenStorage.i.watchKey('theme', onThemeChanged);
TokenStorage.i.unWatchKey('theme', onThemeChanged);
See example/ for full usage of the API.
Testing your own code
This package ships no test doubles. Mock at the platform-interface layer
that flutter_secure_storage and shared_preferences provide for tests.
You'll need to add shared_preferences_platform_interface as a
dev_dependency in your own pubspec.yaml, and call
TestWidgetsFlutterBinding.ensureInitialized() before the mock setup below
runs (typically in setUpAll or at the top of main()):
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:shared_preferences_platform_interface/in_memory_shared_preferences_async.dart';
import 'package:shared_preferences_platform_interface/shared_preferences_async_platform_interface.dart';
setUp(() {
FlutterSecureStorage.setMockInitialValues({});
SharedPreferencesAsyncPlatform.instance = InMemorySharedPreferencesAsync.empty();
});
License
MIT
Libraries
- token_storage
- A Flutter wrapper around
flutter_secure_storagefor managing an auth token pair and generic secure key-value storage.