6

I am working on a flutter application which uses JWT to access backend endpoints. When the access token expires, I added an interceptor to refresh the token based on the solutions provided here: Using Interceptor in Dio for Flutter to Refresh Token I could see server logs which says 401.

Here is my code:

import 'dart:convert';

import 'package:dio/dio.dart';
import 'package:dummy/utils/config.dart';

Future<Response> uploadVideo(filePath, fileName, title, jwt) async {
  Dio dio = new Dio();
  var token = json.decode(jwt);
  dio.interceptors.clear();

  dio.options.headers["Authorization"] = "Bearer ${token['access']}";
  dio.interceptors.add(InterceptorsWrapper(onError: (error) async {
    print(error.response);
    if (error.response?.statusCode == 403 ||
     error.response?.statusCode == 401) {
    await refreshToken(jwt);
    _retry(error.request, dio);
     }
    return error.response;
  }));
  Response response;
  try {
    FormData formData = FormData.fromMap({
      "file_name": fileName,
      "content": await MultipartFile.fromFile(filePath),
      'title': title,
    });
    response = await dio.post("$BASE_URL/video/create/", data: formData);
    return response;
  } on DioError catch (e) {
    if (e.response) {
      print(e.response.data);
      print(e.response.headers);
      print(e.response.request);
    } else {
      // Something happened in setting up or sending the request that triggered an Error
      print(e.request);
      print(e.message);
    }
    return e.response;
  }
}

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

Future<Response> refreshToken(jwt) async {
  print("COMING INSIDE");
  Dio dio = new Dio();
  var token = json.decode(jwt);
  var refreshToken = token['refresh'];
  Response response;
  try {
    FormData formData = FormData.fromMap({
      "refresh": refreshToken,
    });
    response = await dio.post("$BASE_URL/auth/login/refresh/", data: formData);
    return response;
  } catch (e) {
    return e.response;
  }
}

I tried with debugger as well, but its not executing the code after if statement where it checks for 401 and 403. Server clearly gives 401 as I am running it locally so I can see the logs.

What am I doing wrong here?

Thanks in advance.

Maverick
  • 2,738
  • 24
  • 91
  • 157
  • could you provide an output example of `print(error.response);`? – Mol0ko Mar 23 '21 at 16:17
  • Hi, I am getting this ` DioError [DioErrorType.DEFAULT]: SocketException: OS Error: Broken pipe, errno = 32, address = 172.22.22.55, port = 47164.response ` – Maverick Mar 23 '21 at 17:35
  • I could confirm the app reaches the backend server, have login and register screens which works fine. – Maverick Mar 23 '21 at 17:36
  • Did this happen with the upgrade to dio 4? – Anoop Thiruonam Mar 23 '21 at 20:55
  • @Anoop.P.AI didnt upgrade to dio 4, am on 3.0.10, is there a 4 version? I thought the latest is 3.0.10 – Maverick Mar 24 '21 at 05:52
  • Is there any restriction on the file size on the server side? Check [this](https://github.com/flutterchina/dio/issues/492#issuecomment-546660005) – Mariano Córdoba Mar 25 '21 at 16:15
  • Nope, the same endpoint was working fine with sending files before JWT restriction was applied. – Maverick Mar 25 '21 at 16:22
  • As I said earlier as well, I could see my server logs, it says 401 – Maverick Mar 25 '21 at 16:24
  • could you please print out more things and show it in your question. e.g. print out `error.response?.statusCode` in your onError. – ch271828n Mar 27 '21 at 10:19
  • `error.response?.statusCode` is not printing ..its null as error.response is not there – Maverick Mar 27 '21 at 13:40
  • @Maverick could you please give a minimal reproducible sample, then I can debug on it. p.s. please "@ch271828n" otherwise I cannot see your reply – ch271828n Mar 28 '21 at 11:40
  • @Maverick maybe you have a problem with the refresh token itself ? – Hatem Saad Mar 30 '21 at 00:18
  • based on your `print(error.response);` output I think it could be an endpoint issue check [this link](https://github.com/flutterchina/dio/issues/492). I think you need to hadle `if(e.error is SocketException)` case also. – Yashawant Mar 30 '21 at 09:29
  • You are getting a DioErrorType.DEFAULT which has no response and thus also no status code. Only DioErrorType.RESPONSE has a response attached. This also means your error probably has nothing to with the refresh token or the server response. You are likely seeing some problem due to TLS, proxy, connection abort, whatever. Something in between the server and Dio. – kuhnroyal Mar 30 '21 at 10:12
  • Hi @kuhnroyal I could see the logs on the server end, request is reaching there. – Maverick Mar 30 '21 at 14:23
  • 1
    No doubt there but the response is not coming back. The socket is being closed before the response can be read, write timeout, whatever. `SocketException: OS Error: Broken pipe, errno = 32` is your problem. You need to investigate there, I don't think anyone here can help you. – kuhnroyal Mar 30 '21 at 14:33
  • @Maverick print the error object in the first line of your error callback to check which existing DioError types are occurring the error.response exists only if the error type is DioErrorType.response if other error types are happing for example DioErrorType.connectTimeout or DioErrorType.other those have their own problem and they are not related to the status code of the response – Amir Hossein Mirzaei Mar 31 '21 at 09:00
  • @Maverick if your token is based on jwt, you can check token is expired or not with jwt_decoder package instead of adding interceptor – RidvanC Apr 01 '21 at 11:45
  • I face kinda the same thing in dio 3.0.10. Have tried dio 4.0.0? – Nux Apr 05 '21 at 07:51
  • @Nux did it work for you in 4.0.0? Havent tried it yet. – Maverick Apr 05 '21 at 08:29
  • No I haven't but I guess it may work. For your auth flow this issue may offer some help https://github.com/flutterchina/dio/issues/590 – Nux Apr 05 '21 at 10:33

1 Answers1

1

I think the problem is in your Interceptor:

dio.interceptors.add(InterceptorsWrapper(onError: (error) async {
    print(error.response);
    if (error.response?.statusCode == 403 ||
     error.response?.statusCode == 401) {
    await refreshToken(jwt);
    _retry(error.request, dio);
     }
    return error.response;
  }));

You're calling retry method, but:

  • you don't wait for result;
  • you return an error anyway.

Try to add return before _retry instead:

dio.interceptors.add(InterceptorsWrapper(onError: (error) async {
    print(error.response);
    if (error.response?.statusCode == 403 ||
     error.response?.statusCode == 401) {
    await refreshToken(jwt);
    return _retry(error.request, dio);
     }
    return error.response;
  }));
Kirill Bubochkin
  • 5,868
  • 2
  • 31
  • 50
  • Hey, thanks for replying. I would think this could be the case if the execution reaches that if block, but it doest as statuscode is not present. – Maverick Mar 28 '21 at 08:02