Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Interceptor in Dio for Flutter to Refresh Token

I am trying to use Interceptor with Dio in flutter, I have to handle Token expire. following is my code

Future<Dio> getApiClient() async {     token = await storage.read(key: USER_TOKEN);     _dio.interceptors.clear();     _dio.interceptors         .add(InterceptorsWrapper(onRequest: (RequestOptions options) {       // Do something before request is sent       options.headers["Authorization"] = "Bearer " + token;       return options;     },onResponse:(Response response) {         // Do something with response data         return response; // continue     }, onError: (DioError error) async {       // Do something with response error       if (error.response?.statusCode == 403) {         // update token and repeat         // Lock to block the incoming request until the token updated          _dio.interceptors.requestLock.lock();         _dio.interceptors.responseLock.lock();         RequestOptions options = error.response.request;         FirebaseUser user = await FirebaseAuth.instance.currentUser();         token = await user.getIdToken(refresh: true);         await writeAuthKey(token);         options.headers["Authorization"] = "Bearer " + token;          _dio.interceptors.requestLock.unlock();         _dio.interceptors.responseLock.unlock();         _dio.request(options.path, options: options);       } else {         return error;       }     }));     _dio.options.baseUrl = baseUrl;     return _dio;   } 

problem is instead of repeating the network call with the new token, Dio is returning the error object to the calling method, which in turn is rendering the wrong widget, any leads on how to handle token refresh with dio?

like image 336
r4jiv007 Avatar asked Jun 24 '19 16:06

r4jiv007


People also ask

How do you control the refresh token in flutter?

In order to store our refresh token securely in the app, install Flutter Secure Storage by running in the terminal: flutter pub add flutter_secure_storage . Inside the constructor of Api is where we can add the access token to every request using interceptors with dio.

How do you handle a 401k flutter?

When you make a request with an expired access token, the status code 401 (Unauthorized) will appear in the response. In this case, you must request a new token from the server and make the previous request again with a valid access token.

How do I refresh JWTS?

In the URL field enter the address to the refresh token route of your local API - http://localhost:4000/users/refresh-token . Click the Send button, you should receive a "200 OK" response containing the user details and a JWT token, and a cookie containing a new refresh token.


1 Answers

I have found a simple solution that looks like the following:

this.api = Dio();      this.api.interceptors.add(InterceptorsWrapper(        onError: (error) async {           if (error.response?.statusCode == 403 ||               error.response?.statusCode == 401) {               await refreshToken();               return _retry(error.request);             }             return error.response;         }));  

Basically what is going on is it checks to see if the error is a 401 or 403, which are common auth errors, and if so, it will refresh the token and retry the response. My implementation of refreshToken() looks like the following, but this may vary based on your api:

Future<void> refreshToken() async {     final refreshToken = await this._storage.read(key: 'refreshToken');     final response =         await this.api.post('/users/refresh', data: {'token': refreshToken});      if (response.statusCode == 200) {       this.accessToken = response.data['accessToken'];     }   }  

I use Flutter Sercure Storage to store the accessToken. My retry method looks like the following:

  Future<Response<dynamic>> _retry(RequestOptions requestOptions) async {     final options = new Options(       method: requestOptions.method,       headers: requestOptions.headers,     );     return this.api.request<dynamic>(requestOptions.path,         data: requestOptions.data,         queryParameters: requestOptions.queryParameters,         options: options);   }  

If you want to easily allows add the access_token to the request I suggest adding the following function when you declare your dio router with the onError callback:

onRequest: (options) async {           options.headers['Authorization'] = 'Bearer: $accessToken';           return options;         }, 
like image 165
Gabe Avatar answered Oct 04 '22 16:10

Gabe