How to remove Authorization header on redirect on any Flutter/Dart http client

Viewed 1223

I'm currently working on a project which like a lot of other projects works with s3 storage. In this case the storage is linked via the back-end.

The situation is like this, I can get the 'attachment' via an URL, lets say example.com/api/attachments/{uuid}. If the user is authorized (via the header Authorization) it should return a 302 statuscode and redirect to the s3 url. The problem is that after the redirect the Authorization header persists and the http client return a 400 response and it's because of the persisting Authorization header. Is there any way I can remove the Authorization header after redirect without catching the first request and firing a new one?

My http client code currently looks like this:

  @override
  Future get({
    String url,
    Map<String, dynamic> data,
    Map<String, String> parameters,
  }) async {
    await _refreshClient();
    try {
      final response = await dio.get(
        url,
        data: json.encode(data),
        queryParameters: parameters,
      );
      return response.data;
    } on DioError catch (e) {
      throw ServerException(
        statusCode: e.response.statusCode,
        message: e.response.statusMessage,
      );
    }
  }

  Future<void> _refreshClient() async {
    final token = await auth.token;
    dio.options.baseUrl = config.baseUrl;
    dio.options.headers.addAll({
      'Authorization': 'Bearer $token',
      'Accept': 'application/json',
    });
    dio.options.contentType = 'application/json';
  }
2 Answers

Looking at the Dio docs, it seems like this is intentional behaviour.

All headers added to the request will be added to the redirection request(s). However, any body send with the request will not be part of the redirection request(s).

https://api.flutter.dev/flutter/dart-io/HttpClientRequest/followRedirects.html

However, I understand (and agree!) that this is generally undesirable behaviour. My solution is to manually follow the redirects myself, which is not very nice but works in a pinch.

    Response<String> response;
    try {
      response = await dio.get(
        url,
        options: Options(
          // Your headers here, which might be your auth headers
          headers: ...,
          // This is the key - avoid following redirects automatically and handle it ourselves
          followRedirects: false,
        ),
      );
    } on DioError catch (e) {
      final initialResponse = e.response;

      // You can modify this to understand other kinds of redirects like 301 or 307
      if (initialResponse != null && initialResponse.statusCode == 302) {
        response = await dio.get(
          initialResponse.headers.value("location")!, // We must get a location header if we got a redirect
          ),
        );
      } else {
        // Rethrow here in all other cases
        throw e;
      }
    }
Related