secure_token_storage 0.1.0 copy "secure_token_storage: ^0.1.0" to clipboard
secure_token_storage: ^0.1.0 copied to clipboard

Persists OAuth-style access and refresh tokens with separate expiry timestamps in the platform's secure enclave (Android Keystore / iOS Keychain) via flutter_secure_storage.

secure_token_storage #

pub package License: MIT

A tiny, opinionated wrapper around flutter_secure_storage for persisting OAuth-style access + refresh tokens with separate expiry timestamps in the platform's secure enclave (Android Keystore / iOS Keychain).

If you've written this code in three different apps already, this is that code — extracted, tested, and reusable.

Features #

  • One TokenBundle value type holds both tokens and both expiries.
  • isAccessExpired() / isRefreshExpired() helpers with injectable clock for testing.
  • Atomic per-key writes with all-or-nothing read semantics — partial state returns null instead of half-decoded garbage.
  • keyPrefix for multi-account or dev/staging isolation on the same device.
  • Pure flutter_secure_storage under the hood: no extra native code, no extra permissions.

Install #

flutter pub add secure_token_storage

Usage #

import 'package:secure_token_storage/secure_token_storage.dart';

final storage = const SecureTokenStorage();

// After successful login:
await storage.save(
  TokenBundle(
    accessToken: response.accessToken,
    refreshToken: response.refreshToken,
    accessExpiresAt:
        DateTime.now().toUtc().add(Duration(seconds: response.expiresIn)),
    refreshExpiresAt:
        DateTime.now().toUtc().add(const Duration(days: 30)),
  ),
);

// On app start:
final tokens = await storage.read();
if (tokens == null || tokens.isRefreshExpired()) {
  // user must log in again
} else if (tokens.isAccessExpired()) {
  // call your refresh endpoint, then storage.save(...) the new bundle
} else {
  // use tokens.accessToken
}

// On logout:
await storage.clear();

Multi-account / staging isolation #

final prod = const SecureTokenStorage();
final staging = const SecureTokenStorage(keyPrefix: 'staging_');

The two stores never collide — clear() on one leaves the other intact.

API #

TokenBundle #

Field Type Notes
accessToken String Sent as Authorization: Bearer ….
refreshToken String Used to mint a new access token.
accessExpiresAt DateTime Stored as ISO-8601 UTC.
refreshExpiresAt DateTime Stored as ISO-8601 UTC.
Method Returns
isAccessExpired({DateTime? now}) true when now ≥ accessExpiresAt.
isRefreshExpired({DateTime? now}) true when now ≥ refreshExpiresAt.

SecureTokenStorage #

Constructor parameter Default Notes
storage platform default Inject your own for testing.
keyPrefix '' Namespaces every entry.
Method Behavior
save(TokenBundle) Writes all 4 entries.
read() Returns the bundle, or null if any entry is missing.
clear() Deletes all 4 entries under the configured prefix.

Testing your own code #

SecureTokenStorage accepts an injected FlutterSecureStorage so you can mock it. See test/secure_token_storage_test.dart for a worked example using mocktail.

flutter test

Example app #

A small interactive demo lives in example/:

cd example
flutter run

License #

MIT — see LICENSE.

0
likes
140
points
9
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Persists OAuth-style access and refresh tokens with separate expiry timestamps in the platform's secure enclave (Android Keystore / iOS Keychain) via flutter_secure_storage.

Repository (GitHub)
View/report issues

Topics

#authentication #token #oauth #keychain #keystore

License

MIT (license)

Dependencies

flutter, flutter_secure_storage

More

Packages that depend on secure_token_storage