facebook / react-native

A framework for building native applications using React
https://reactnative.dev
MIT License
119.26k stars 24.35k forks source link

[iOS] Authorization header dropped when making HTTP requests that redirect #34627

Open fawad-khalil-retailo opened 2 years ago

fawad-khalil-retailo commented 2 years ago

Description

I am requesting a URL of API service which responds with status code 307 (redirect) on success and a URL location in response Headers. This is protected API and needs Authorization header for it to be fulfilled successfully. The problem I am facing is that the Authorization header is not appended to the redirected URL, it is only appended to the original call, and therefore the redirected URL call fails with status 401. This works perfectly fine in Postman but is not working with Axios. This works fine in ReactJS web app and React Native mobile on Android OS, too. The problem is only on iOS platform. I have tried on a bare minimum RN app v.69.5 and v0.67.4 using axios and fetch API and the results on iOS platform are the same, so it clearly is problem on iOS platform with React Native. There is one more strange behaviour, it works fine on iOS, too, if I connect the app with react-native-debugger and inspect the network calls. So the problem is only on iOS platform with chrome debugger disabled. I have tried using maxRedirects: 0 prop and beforeRedirect callback on axios but to no avail.

Version

[0.67.4, 0.69.5]

Output of npx react-native info

info Fetching system and libraries information... System: OS: macOS 12.4 CPU: (8) arm64 Apple M1 Memory: 313.20 MB / 16.00 GB Shell: 5.8.1 - /bin/zsh Binaries: Node: 16.13.0 - ~/.nvm/versions/node/v16.13.0/bin/node Yarn: 1.22.17 - ~/.nvm/versions/node/v16.13.0/bin/yarn npm: 8.1.4 - ~/.nvm/versions/node/v16.13.0/bin/npm Watchman: Not Found Managers: CocoaPods: 1.11.3 - /usr/local/bin/pod SDKs: iOS SDK: Platforms: DriverKit 21.4, iOS 15.5, macOS 12.3, tvOS 15.4, watchOS 8.5 Android SDK: Not Found IDEs: Android Studio: 2020.3 AI-203.7717.56.2031.7784292 Xcode: 13.4.1/13F100 - /usr/bin/xcodebuild Languages: Java: 12.0.2 - /usr/bin/javac npmPackages: @react-native-community/cli: Not Found react: 17.0.2 => 17.0.2 react-native: 0.67.4 => 0.67.4 react-native-macos: Not Found npmGlobalPackages: react-native: Not Found

Steps to reproduce

  1. npx react-native init sampleapp --version 0.69.5
  2. yarn add axios query-string
  3. Add the imports on top:
    import axios from 'axios';
    import queryString from 'query-string';
  4. Place the following snippet in App.js file:
    const apply = async () => {
    const url = `https://${baseUrl}/coupons/apply`;
    const token = 'token';
    const ins = axios.create({headers: {Authorization: token}});
    const data = {
      coupon: {
        name: 'SufrExelBL',
      },
      ],
    };
    const params = {
      calculateTotal: true,
    };
    const headers = {
      Authorization: token,
    };
    try {
      const res = await ins.put(url, data, {
        params,
        paramsSerializer: function (params) {
          return queryString.stringify(params);
        },
        headers,
      });
      console.log('SUCCESSSSSSSSSSSSSS', res);
    } catch (e) {
      console.log('ERORROOOOOORRRRRRRr', e);
    }
    };
    useEffect(() => {
    apply();
    }, []);
  5. Note the catch block got executed with error 401 returned

Snack, code example, screenshot, or link to a repository

https://snack.expo.dev/mhWvbpbX6

github-actions[bot] commented 2 years ago
:warning: Missing Environment Information
:information_source: Your issue may be missing information about your development environment. You can obtain the missing information by running react-native info in a console.
fawad-khalil-retailo commented 2 years ago

Updated the react-native info output

fawad-khalil-retailo commented 2 years ago

@hramos Please help

fawad-khalil-retailo commented 2 years ago

I had tried building 0.70.0 as well to test it out but failed due to this https://github.com/harfbuzz/harfbuzzjs/issues/34.

fawad-khalil-retailo commented 2 years ago

It is a dup of https://github.com/facebook/react-native/issues/26311 but couldn't find its solution at that link.

raduciobanu22 commented 2 years ago

Have the same issue when building on a Mac device with M1 chip. If instead I build the app on a Mac with Intel chip everything works.

yoovin commented 1 year ago

Has anyone solved this issue in the m1 chip environment?

srascar-bubble commented 1 year ago

Hello, @raduciobanu22 , not sure this is linked to m1. We faced the same issue on non m1 chip. There is already an attempt to fix that issue https://github.com/facebook/react-native/blob/714b502b0c7a5f897432dbad388c02d3b75b4689/packages/react-native/Libraries/Network/RCTHTTPRequestHandler.mm#L145

However, this does not cover for Authorization header. Furthermore, the request object received is already missing the original headers.

Here is a patch that you can apply that reads the header from the original request.

diff --git a/node_modules/react-native/Libraries/Network/RCTHTTPRequestHandler.mm b/node_modules/react-native/Libraries/Network/RCTHTTPRequestHandler.mm
index 7b54592..66a2983 100644
--- a/node_modules/react-native/Libraries/Network/RCTHTTPRequestHandler.mm
+++ b/node_modules/react-native/Libraries/Network/RCTHTTPRequestHandler.mm
@@ -146,6 +146,14 @@ - (void)URLSession:(NSURLSession *)session

   NSArray<NSHTTPCookie *> *cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookiesForURL:request.URL];
   nextRequest.allHTTPHeaderFields = [NSHTTPCookie requestHeaderFieldsWithCookies:cookies];
+    
+  NSString *originalAuthorizationHeader = [task.originalRequest valueForHTTPHeaderField:@"Authorization"];
+   
+  // forward the original Authorization if set
+  if (originalAuthorizationHeader) {
+    [nextRequest addValue:originalAuthorizationHeader forHTTPHeaderField:@"Authorization" ];
+  }
+
   completionHandler(nextRequest);
 }

Please note that this is based on react-native@0.68.5 Happy to open a PR since I think this should be fixed

shibatanien commented 10 months ago

@fawad-khalil-retailo I had the exact same issue. Sending a request using Postman and from the web works perfectly fine, but Authorization header seems to be removed only when requesting from iOS device. Adding / to the end of the URL seemed to solve this issue for me. For your example code snippet, changing the url variable from https://${baseUrl}/coupons/apply to https://${baseUrl}/coupons/apply/

FoRavel commented 10 months ago

@fawad-khalil-retailo I had the exact same issue. Sending a request using Postman and from the web works perfectly fine, but Authorization header seems to be removed only when requesting from iOS device. Adding / to the end of the URL seemed to solve this issue for me. For your example code snippet, changing the url variable from https://${baseUrl}/coupons/apply to https://${baseUrl}/coupons/apply/

Thank you, it solved my problem.

It's an unlikely reason and I can't explain it, but I also solved the problem by adding a "/" at the end of the URL.

skoolaidl commented 6 months ago

@fawad-khalil-retailo I had the exact same issue. Sending a request using Postman and from the web works perfectly fine, but Authorization header seems to be removed only when requesting from iOS device. Adding / to the end of the URL seemed to solve this issue for me. For your example code snippet, changing the url variable from https://${baseUrl}/coupons/apply to https://${baseUrl}/coupons/apply/

This worked for me.

YamanKtish commented 2 months ago

@fawad-khalil-retailo I had the exact same issue. Sending a request using Postman and from the web works perfectly fine, but Authorization header seems to be removed only when requesting from iOS device. Adding / to the end of the URL seemed to solve this issue for me. For your example code snippet, changing the url variable from https://${baseUrl}/coupons/apply to https://${baseUrl}/coupons/apply/

Thank you @shibatanien ! this worked for me.

angryalok commented 3 weeks ago

Thank you worked for me

tbd-sayeed commented 2 weeks ago

Thank you @shibatanien this worked for me :)