If the expiration of the token is less than 3580 seconds, I want to update my access token with my refresh request before the new request I will send. And then I want to throw out my new request.
But when the refresh function calls, I enter the loop and get a 401 error. Then my onError method works and I am redirected to the login screen. How do I get out of this cycle? And how can I renew my token by checking my disappearance period before each request I will send?
My TokenExpireHelper class returns my expiration time by encoding the token from the shared value.
class AuthInterceptor extends QueuedInterceptorsWrapper {
final Dio _dio;
late final IUserServices _loginManager = UserServices();
bool _isRefreshing = false;
AuthInterceptor(this._dio);
@override
Future<void> onRequest(RequestOptions options, RequestInterceptorHandler handler) async {
if (options.headers["requiresToken"] == false) {
// if the request doesn't need token, then just continue to the next interceptor
options.headers.remove("requiresToken"); //remove the auxiliary header
return handler.next(options);
}
bool accessTokenHasExpired = TokenExpireHelper().getExpireTime() < 3580 ? true : false;
if (accessTokenHasExpired) {
if (!_isRefreshing) {
_isRefreshing = true;
_loginManager.refreshToken().whenComplete(() => _isRefreshing = false);
// Update the request header with the new access token
if (access_token.$ != "") {
options.headers['Authorization'] = 'Bearer ${access_token.$}';
// Repeat the request with the updated header
return handler.next(options);
}
}
}
print('REQUEST[${options.method}] => PATH: ${options.path}');
return super.onRequest(options, handler);
}
@override
Future<void> onError(DioException e, ErrorInterceptorHandler handler) async {
if (e.response?.statusCode == 403 || e.response?.statusCode == 401) {
// for some reasons the token can be invalidated before it is expired by the backend.
// then we should navigate the user back to login page
OneContext.instance.key.currentState!.pushNamedAndRemoveUntil("/signInView", (Route<dynamic> route) => false);
}
print(e.response?.statusCode);
return handler.next(e);
}
------- refresh function ( this function inside UserService class )
@override
Future<bool> refreshToken() async {
final response = await _reqresManager.post(
_RezyonRequestPaths.refresh.name,
options: Options(headers: {
"Content-Type": "application/json",
"Authorization": "Bearer ${access_token.$}",
}),
);
if (response.statusCode == HttpStatus.ok) {
final String accessToken = response.data["access_token"];
final int expireDate = response.data["expires_in"];
print(accessToken);
await access_token.load();
access_token.$ = accessToken;
await access_token.save();
await expires_in.load();
expires_in.$ = expireDate;
await expires_in.save();
print("refresh token works");
return response.statusCode == HttpStatus.ok;
}
return false;
}