Summary
The Flutter application fails to fetch data after 4-5 days of inactivity due to expired authentication tokens. The app UI loads without errors but remains data-less until manual logout/login. This highlights the critical need for robust token management in authentication systems.
Root Cause
- Token expiry: Backend-issued JWT tokens have a limited lifespan (e.g., 24-48 hours). After expiry, API requests return
401 Unauthorizederrors. - No token refresh logic: The app lacks an automated token refresh mechanism. It continues using stale tokens without attempting renewal.
- Missing session validation: No checks for token expiration before making API calls.
- Silent failure: The app doesn’t handle
401errors transparently, leaving users stuck at a non-functional UI.
Why This Happens in Real Systems
- Security practices: Short-lived tokens reduce attack windows but require refresh workflows.
- Stateless APIs: JWTs are stateless, so token validation logic must reside entirely on the client.
- Background latency: Network issues during token refresh can cause race conditions if not handled.
- Platform limitations: Mobile apps may be killed by the OS, losing in-memory token state and forcing re-authentication.
Real-World Impact
- User frustration: App appears broken, requiring manual re-authentication.
- Increased support tickets: Users report “app not working” instead of token expiry.
- Revenue loss: In e-commerce apps, abandoned carts during recovery flows.
- API overload: High failed
401requests waste backend resources. - Reputation damage: Users perceive the app as unreliable.
Example or Code
import 'dart:async';
import 'package:dio/dio.dart';
class AuthInterceptor extends Interceptor {
final Dio dio;
String? refreshToken;
Timer? _refreshTimer;
AuthInterceptor(this.dio, {this.refreshToken});
@override
Future onError(DioException err, ErrorInterceptorHandler handler) async {
if (err.response?.statusCode == 401) {
try {
await _refreshAccessToken();
// Retry original request with new token
final options = err.requestOptions;
options.headers['Authorization'] = 'Bearer $refreshToken';
return handler.resolve(await dio.fetch(options));
} catch (e) {
_clearSession();
return handler.resolve(Response(
requestOptions: err.requestOptions,
statusCode: 401,
data: null,
));
}
}
return handler.next(err);
}
Future _refreshAccessToken() async {
final response = await dio.post('/auth/refresh', data: {'token': refreshToken});
refreshToken = response.data['token'];
_scheduleRefresh(response.data['expires_in']);
}
void _scheduleRefresh(int expirySeconds) {
_refreshTimer?.cancel();
_refreshTimer = Timer(Duration(seconds: expirySeconds ~/ 2), _refreshAccessToken);
}
void _clearSession() {
refreshToken = null;
_refreshTimer?.cancel();
}
}
// Usage
final dio = Dio();
dio.interceptors.add(AuthInterceptor(dio, refreshToken: 'current_token'));
How Senior Engineers Fix It
- Implement token refresh flows:
- Use short-lived access tokens + long-lived refresh tokens
- Automatically refresh tokens before expiry (e.g., 50% through lifespan)
- Add retry logic:
- Intercept
401errors and trigger refresh without user intervention
- Intercept
- Expiry checks:
- Validate token expiry timestamps before API calls
- Graceful degradation:
- Show spinner during token refresh
- Fallback to cached data while refreshing
- Secure storage:
- Encrypt tokens in secure storage (iOS Keychain/Android Keystore)
- Session timeout UX:
- Auto-redirect to login after repeated refresh failures
Why Juniors Miss It
- Token lifecycle misunderstanding: Assuming tokens remain valid indefinitely
- Error handling oversights: Not handling
401responses comprehensively - Refresh token concept: Unaware of refresh token architecture patterns
- State management gaps: Not persisting tokens across app restarts
- Testing limitations: Not simulating delayed token expiry scenarios
- Security tradeoffs: Prioritizing UX over token expiration best practices
Key Takeaway: Token expiry is inevitable in production systems. Proactive refresh handling transforms a critical bug into a seamless user experience. Always validate tokens and plan for renewal before expiry.