Reputation: 21
I'm new to Flutter and using the http package for network calls.
My goal is to refresh the token and retry the request if the access token has expired. I’ve seen the Dio package mentioned, but it seems complicated to me, so I’d prefer to stick with http.
Problem:
I want to:
Check if the access token has expired before making an API call.
If expired, call the refresh token API to get a new token.
Retry the original request with the new token.
This my app flutter:
This login function to POST accesstoken
static Future<bool> loginUser(String email, String password) async {
try {
var reqBody = {"email": email, "password": password};
var response = await http.post(
Uri.parse(login),
headers: {"Content-Type": "application/json"},
body: jsonEncode(reqBody),
);
var jsonResponse = jsonDecode(response.body);
if (jsonResponse['status']) {
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setString('token', jsonResponse['token']);
prefs.setString('refreshToken', jsonResponse['refreshToken']);
return true;
} else {
return false;
}
} catch (error) {
throw Exception('Failed to login user: $error');
}
}
static DateTime? lastApiCallTime;
static Future<void> checkAndRefreshToken() async {
if (lastApiCallTime != null &&
DateTime.now().difference(lastApiCallTime!).inMinutes < 3) {
return;
}
lastApiCallTime = DateTime.now();
await refreshAccessToken();
}
static Future<bool> refreshAccessToken() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
String? refreshToken = prefs.getString('refreshToken');
if (refreshToken == null) {
throw Exception('No refresh token found');
}
try {
var response = await http.post(
Uri.parse(refreshTokenUrl),
headers: {"Content-Type": "application/json"},
body: jsonEncode({'refreshToken': refreshToken}),
);
if (response.statusCode == 200) {
var jsonResponse = jsonDecode(response.body);
prefs.setString('token', jsonResponse['token']);
print('New token: ${jsonResponse['token']}');
return true;
} else {
return false;
}
} catch (error) {
print('Failed to refresh token: $error');
return false;
}
}
I’m not sure how to properly retry the original request after refreshing the token.
How can I: Detect when the token has expired (e.g., response 401 or similar). Automatically refresh the token and retry the request with the new token.
Upvotes: 1
Views: 82
Reputation: 132
You can try recursivity. Something like this should do it :
Future<void> recursiveAPICall() async {
final response = await http.get(Uri.parse(apiLink));
if (response.statusCode == 200) {
// do your logic
} else if (response.statusCode == 401){
// check for the accesstoken expiration and get another one
recursiveAPICall()
}
}
EDIT :
Integrating it with your code, something like that:
Future<void> recursiveAPICall() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
String? token = prefs.getString('token');
String? refreshToken = prefs.getString('refreshToken');
if (refreshToken == null) {
throw Exception('No refresh token found');
}
var response = await http.get(
Uri.parse(apiLink),
headers: {"Authorization": "Bearer $token"},
);
if (response.statusCode == 200) {
// Do your logic here
print('API call successful');
} else if (response.statusCode == 401) {
// Token might be expired, try to refresh it
var refreshResponse = await http.post(
Uri.parse(refreshTokenUrl),
headers: {"Content-Type": "application/json"},
body: jsonEncode({'refreshToken': refreshToken}),
);
if (refreshResponse.statusCode == 200) {
var jsonResponse = jsonDecode(refreshResponse.body);
prefs.setString('token', jsonResponse['token']);
print('New token: ${jsonResponse['token']}');
// Retry the API call after refreshing the token
await recursiveAPICall();
} else {
print('Failed to refresh token, cannot proceed with API call');
}
} else {
print('API call failed with status: ${response.statusCode}');
}
}
Upvotes: 0