token_storage 1.2.0
token_storage: ^1.2.0 copied to clipboard
A Flutter wrapper around flutter_secure_storage for managing an auth token pair and generic secure key-value storage, with fresh-install cleanup.
example/lib/main.dart
import 'package:flutter/material.dart';
import 'package:token_storage/token_storage.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await TokenStorage.init();
runApp(const TokenStorageExampleApp());
}
class TokenStorageExampleApp extends StatelessWidget {
const TokenStorageExampleApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(title: 'token_storage example', home: const HomePage());
}
}
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
String _status = 'No token';
final _nameController = TextEditingController();
String? _storedName;
_Note? _storedNote;
@override
void initState() {
super.initState();
TokenStorage.i.setTokenListener(_onTokenChanged);
_refreshStatus();
}
@override
void dispose() {
TokenStorage.i.removeTokenListener();
_nameController.dispose();
super.dispose();
}
void _onTokenChanged(TokenPair? token) {
setState(() {
_status = token == null
? 'Logged out (listener fired)'
: 'Logged in (listener fired)';
});
}
Future<void> _refreshStatus() async {
final hasToken = await TokenStorage.i.hasToken;
if (!mounted) return;
setState(() => _status = hasToken ? 'Has token' : 'No token');
}
Future<void> _login() async {
final now = DateTime.now();
await TokenStorage.i.saveToken(
TokenPair(
accessToken: 'demo-access-${now.millisecondsSinceEpoch}',
refreshToken: 'demo-refresh-${now.millisecondsSinceEpoch}',
createdAt: now,
updatedAt: now,
),
);
}
Future<void> _silentlyRefresh() async {
final current = await TokenStorage.i.token;
if (current == null) return;
await TokenStorage.i.updateToken(
TokenPair(
accessToken: 'demo-access-refreshed',
refreshToken: current.refreshToken,
createdAt: current.createdAt,
updatedAt: DateTime.now(),
),
);
if (!mounted) return;
await _refreshStatus();
}
Future<void> _logout() => TokenStorage.i.clearToken();
Future<void> _saveName() async {
await TokenStorage.i.put('display_name', _nameController.text);
if (!mounted) return;
final stored = await TokenStorage.i.get('display_name');
if (!mounted) return;
setState(() => _storedName = stored);
}
Future<void> _saveNote() async {
await TokenStorage.i.putObject(
'last_note',
_Note(text: _nameController.text, createdAt: DateTime.now()),
(note) => note.toJson(),
);
if (!mounted) return;
final note = await TokenStorage.i.getObject('last_note', _Note.fromJson);
if (!mounted) return;
setState(() => _storedNote = note);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('token_storage example')),
body: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text('Status: $_status'),
const SizedBox(height: 16),
ElevatedButton(
onPressed: _login,
child: const Text('Login (saveToken)'),
),
ElevatedButton(
onPressed: _silentlyRefresh,
child: const Text('Silent refresh (updateToken)'),
),
ElevatedButton(
onPressed: _logout,
child: const Text('Logout (clearToken)'),
),
const Divider(height: 32),
TextField(
controller: _nameController,
decoration: const InputDecoration(labelText: 'Display name'),
),
ElevatedButton(
onPressed: _saveName,
child: const Text('Save name (put/get)'),
),
if (_storedName != null) Text('Stored name: $_storedName'),
const Divider(height: 32),
ElevatedButton(
onPressed: _saveNote,
child: const Text('Save note (putObject/getObject)'),
),
if (_storedNote != null)
Text(
'Stored note: ${_storedNote!.text} (${_storedNote!.createdAt})',
),
],
),
),
);
}
}
/// A tiny typed object used to demonstrate [TokenStorage.putObject] and
/// [TokenStorage.getObject], which store/retrieve JSON-serializable objects
/// instead of raw strings.
class _Note {
const _Note({required this.text, required this.createdAt});
final String text;
final DateTime createdAt;
Map<String, dynamic> toJson() => {
'text': text,
'createdAt': createdAt.toIso8601String(),
};
factory _Note.fromJson(Map<String, dynamic> json) => _Note(
text: json['text'] as String,
createdAt: DateTime.parse(json['createdAt'] as String),
);
}