-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Repeat a request after getting a fresh JWT token on 401 #50
Comments
same issue here. |
Another idea is to decode the JWT token in an interceptor and get it's expiry date; if it is expired or about to expire, it could be refreshed and replaced before the request continues. Sounds like a clean solution, but I haven't tried it yet. As I said, I'm still evaluating which library to use. And I was curious to hear about experiences from others how to deal with it. |
@ToniTornado @zinwalin Have you read this example? String csrfToken; //top-level variable
dio.interceptor.response.onError = (DioError error) {
if(error.response?.statusCode==401){
Options options=error.response.request;
// If the token has been updated, repeat directly.
if(csrfToken!=options.headers["csrfToken"]){
options.headers["csrfToken"]=csrfToken;
//repeat
return dio.request(options.path,options: options);
}
// update token and repeat
// Lock to block the incoming request until the token updated
dio.interceptor.request.lock();
dio.interceptor.response.lock();
return tokenDio.get("/token").then((d) {
//update csrfToken
options.headers["csrfToken"] = csrfToken = d.data['data']['token'];
}).whenComplete((){
dio.interceptor.request.unlock();
dio.interceptor.response.unlock();
}).then((e){
//repeat
return dio.request(options.path,options: options);
});
}
return error;
}; |
such method wont working properly when multiple requests enqueued. |
I also met the same question . In my project , inside "onError" , |
Same problem, refresh code enter into loop of requests |
The following solution/hack seems to work for me. Just keep track of a number (maybe a boolean would also work). When a request is successful or when there is an error while the counter is uneven (1) set the _repeatCounter to 0 (even number). The code is not battle tested (what happens i.e. when you make multiple requests simultaneously?).
|
Any Update? |
I've just run into a similar issue and followed the code that was used on the test 'Interceptor error lock: test' found here: https://github.com/flutterchina/dio/blob/master/dio/test/interceptor_test.dart. It worked flawlessly except from the fact that you must keep track of how many refreshes you have already tried. This is important so you don't get in a loop and instead just logout the user. This can be done by using a request header with a
|
|
I've created a gist with the retry-count example. This code is based on this test I mentioned earlier. https://gist.github.com/douglasiacovelli/8fe98ec4a98e72bef5da1189a19fb3b9 |
import 'dart:io';
import 'package:dio/dio.dart';
import 'package:shared_preferences/shared_preferences.dart';
class Request {
var _dio = Dio();
Dio refreshDio = Dio();
final String _baseUrl =
Platform.isAndroid ? 'http://10.0.2.2:8000' : 'http://localhost:8000';
Future<Dio> networkInterCeptor() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
String token = prefs.getString('token');
String refreshToken = prefs.getString('refreshToken');
print('Refresh Token $refreshToken');
print('Old Token $token');
_dio.interceptors.clear();
_dio.options.baseUrl = _baseUrl;
_dio.interceptors.add(InterceptorsWrapper(onRequest: (RequestOptions
options) {
options.headers['content-Type'] = 'application/json';
options.headers['Accept'] = 'application/json';
if (token != null) {
print('token hai $token');
options.headers["Authorization"] = 'Bearer $token';
}
return options;
}, onResponse: (Response response) {
// Do something with response data
print('Interceptor$response');
return response; // continue
}, onError: (DioError error) async {
print('Error Response ${error.response}');
print('Error Response ${error.response.statusCode}');
if (error.response.statusCode == 401) {
RequestOptions options = error.response.request;
print('Authorization header is ${options.headers['Authorization']}');
if (options.headers['Authorization'] != 'Bearer $token') {
return _dio.request(options.path, options: options);
} else {
_lockDio();
if (options.headers['Retry-Count'] == 1) {
_unlockDio();
print('Hello${options.headers['Retry-Count']}');
// Here you might want to logout the user
return error;
}
print('Refresh Token inside $refreshToken');
refreshDio.post("http://localhost:8000/api/refreshtoken",data: {
"refresh_token": refreshToken}).then((response) {
print('response Refresh token api $response.data');
var newAccessToken = response.data['access_token'];
prefs.setString("token", newAccessToken);
options.headers["Authorization"] = 'Bearer $newAccessToken';
print('new TOKEn$newAccessToken');
}).whenComplete(() {
_unlockDio();
}).then((e) {
options.headers['Retry-Count'] = 1;
return _dio.request(options.path, options: options);
}).catchError((e) {
print('hello error');
// Here you might want to logout the user
return e;
});
}
} else {
return error;
}
}));
return _dio;
}
void _lockDio() {
_dio.lock();
// _dio.interceptors.requestLock.lock();
_dio.interceptors.responseLock.lock();
_dio.interceptors.errorLock.lock();
}
void _unlockDio() {
_dio.unlock();
// _dio.interceptors.requestLock.unlock();
_dio.interceptors.responseLock.unlock();
_dio.interceptors.errorLock.unlock();
}
}
Hello Sir ,I am beginner in fluttter ,this code is not working for me
,please help.
When token is expired i want to make server request to get new access
token and refresh token
… |
I am also getting infinite loop |
after upgrading to 4.x this no longer works, I get
Anyone else faced this? Of course, you can always do:
|
Following updating to version 4.x, I found that I needed to change my onError handler from: Future onError(DioError err) async {
...
return retryDio.request(...);
} To the new handler signature and approach: Future onError(DioError err, ErrorInterceptorHandler handler) async {
...
try {
final response = await retryDio.request(...);
return handler.resolve(response);
} on DioError catch (e) {
return handler.reject(e);
}
} |
@vimalmistry I have shared a code snippet to handle 401 errors here: #1088 (comment) |
@vimalmistry from @mauriziopinotti solution, you just have to change return dio.request(error.requestOptions.path, options: error.requestOptions to return dio.fetch(options); This will take care of passing all details about the failed request. |
Improve the workflow configuration between packages. ![image](https://user-images.githubusercontent.com/15884415/209802430-a9e056d9-cac0-401f-b0c2-c01c4e10008c.png) ![image](https://user-images.githubusercontent.com/15884415/209802389-3c181742-4175-47ed-823f-a9f0eea8048a.png)
I'm considering to switch my app repositories to use dio for all http requests, it looks really promising!
What is the best approach to refresh a JWT token with dio? Is there an easy way to get a fresh token and repeat the request with the fresh token after it got a 401?
The text was updated successfully, but these errors were encountered: