How to Refresh Token Using Interceptor In Dio for Flutter

How to Refresh Token Using Interceptor In Dio for Flutter ??

In order to request a new access token, you need to use the post method along with form data and required Dio’s options content-type and headers. So in this article, we will go through How to Refresh Token Using Interceptor In Dio for Flutter.

How to Refresh Token Using Interceptor In Dio for Flutter ??

After a successful request, if you get the response status code is 200, then you will get a new access token value along with a refresh token value and save them in any storage you prefer to use. For example, Shared preferences.

Once you have a new access token saved, you can use it to fetch data using the get method shown in the same code below.

onError(DioError error) async {
    if (error.response?.statusCode == 401) {
      Response response;
      var authToken = base64
          .encode(utf8.encode("username_value" + ":" + "password_value"));
      FormData formData = new FormData.from(
          {"grant_type": "refresh_token", "refresh_token": refresh_token_value});
      response = await dio.post(
        url,
        data: formData,
        options: new Options(
            contentType: ContentType.parse("application/x-www-form-urlencoded"),
            headers: {HttpHeaders.authorizationHeader: 'Basic $authToken'}),
      );
      if (response.statusCode == 200) {
        response = await dio.get(
          url,
          options: new Options(headers: {
            HttpHeaders.authorizationHeader: 'Bearer access_token_value'
          }),
        );
        return response;
      } else {
        print(response.data);
        return null;
      }
    }
    return error;
  }

I solved it using interceptors in the following way:-

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) {
      _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();
      return _dio.request(options.path,options: options);
    } else {
      return error;
    }
  }));
  _dio.options.baseUrl = baseUrl;
  return _dio;
}

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'];
    }
  }

We can also use flutter secure storage to store the accessToken. My retry method looks like the following:

If you want to easily allows add the access_token to the request.

The recommended thing is to, add the following function when you declare your dio router with the onError callback:

onRequest: (options) async {
          options.headers['Authorization'] = 'Bearer: $accessToken';
          return options;
        },

Consider a code snippet like the below:

RestClient client;
        
          static BaseOptions options = new BaseOptions(
            connectTimeout: 5000,
            receiveTimeout: 3000,
          );
          RemoteService() {
            // or new Dio with a BaseOptions instance.
            final dio = Dio(options);
        
            dio.interceptors
                .add(InterceptorsWrapper(onRequest: (RequestOptions options) async {
              // Do something before request is sent
              return options; //continue
            }, onResponse: (Response response) async {
              // Do something with response data
              return response; // continue
            }, onError: (DioError error) async {
              // Do something with response error
              if (error.response.statusCode == 401) {
                Response response =
                    await dio.post("http://addrees-server/oauth/token",
                        options: Options(
                          headers: {
                            'Authorization': ApiUtils.BASIC_TOKEN,
                            'Content-Type': ApiUtils.CONTENT_TYPE,
                          },
                        ),
                        queryParameters: {
                      "grant_type": ApiUtils.GRANT_TYPE,
                      "username": AppConstants.LOGIN,
                      "password": AppConstants.PASSWORD
                    });
        
                Sessions.access_token = response.data['access_token'];
        
                error.response.request.queryParameters
                    .update('access_token', (value) => Sessions.access_token);
                RequestOptions options = error.response.request;
        
                return dio.request(options.path, options: options); //continue
              } else {
                return error;
              }
            }));
            client = RestClient(dio);
          }

Conclusion:

Thanks for reading !!! Stay Connected 🙂

In this article, we have been through how to refresh token using interceptor in Dio for flutter.

Keep Learning !!! Keep Fluttering !!!

Flutter Agency is our portal Platform dedicated to Flutter Technology and Flutter Developers. The portal is full of cool resources from Flutter like Flutter Widget Guide, Flutter Projects, Code libs and etc.

Flutter Agency is one of the most popular online portals dedicated to Flutter Technology and daily thousands of unique visitors come to this portal to enhance their knowledge of Flutter.

Nirali Patel

Written by Nirali Patel

Nirali Patel is a dedicated Flutter developer with over two years of experience, specializing in creating seamless mobile applications using Dart. With a passion for crafting user-centric solutions, Nirali combines technical proficiency with innovative thinking to push the boundaries of mobile app development.

Leave a comment

Your email address will not be published. Required fields are marked *


ready to get started?

Fill out the form below and we will be in touch soon!

"*" indicates required fields

✓ Valid number ✕ Invalid number