Handle access token expiration with a single refresh request, even when many API calls run concurrently. Calls that find an expired token wait for the refresh already in progress instead of starting their own.
This pattern is published as a plugin: flutter_secure_token_manager. It stores tokens securely and manages refresh for you. Use this demo if you want the code in your own project and full control over it.
-
Add the dependencies:
dependencies: flutter_secure_storage: ^11.2.0 http: ^1.6.0 jwt_decoder: ^2.0.1
-
Copy these into your project:
lib/auth/token_manager.dart: refresh logic and request de-duplicationlib/auth/token_storage.dart: persistence (SecureTokenStorageusesflutter_secure_storage)lib/auth/session_expired_exception.dartlib/models/token.dart: adjust the fields andfromJsonif your token response differs
-
Create the manager with a
refresher, a function that exchanges the refresh token for a newToken. Throw anApiExceptionwith the HTTP status on failure (seelib/api/auth_api.dart).final tokenManager = TokenManager( refresher: authApi.getNewAccessToken, storage: const SecureTokenStorage(), );
-
On app start, call
await tokenManager.load()to restore a saved session. After a successful login, callawait tokenManager.setToken(token). On logout, callawait tokenManager.clear(). -
Attach the token to every authenticated request. Any HTTP client works (http, dio, others):
headers: {"Authorization": "Bearer ${await tokenManager.getAccessToken()}"}
getAccessTokenrefreshes the token first if it is expired. If the refresh token is rejected (400/401), the session is cleared andSessionExpiredExceptionis thrown: catch it and send the user to login. -
If your tokens are not JWTs, change
isTokenExpiredinTokenManager.
See lib/api/api_client.dart for a complete request example and test/token_manager_test.dart for
the concurrent refresh behavior.
flutter pub get
flutter run
Tap Login, then Expire token and send requests. The activity timeline shows a single refresh with the other requests waiting on it.