From ba541a1ef6986c0b48646c702815a8765abd0a17 Mon Sep 17 00:00:00 2001 From: Oskar Eichler Date: Sat, 5 Sep 2026 01:55:08 +0700 Subject: [PATCH] fix: block redirects when custom headers are present --- .changeset/brave-owls-redirect.md | 5 +++++ docs/docs/usage/config.md | 4 ++++ .../rnappauth/utils/CustomConnectionBuilder.java | 3 ++- packages/react-native-app-auth/ios/RNAppAuth.m | 15 +++++++++++++-- 4 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 .changeset/brave-owls-redirect.md diff --git a/.changeset/brave-owls-redirect.md b/.changeset/brave-owls-redirect.md new file mode 100644 index 000000000..39c4eee21 --- /dev/null +++ b/.changeset/brave-owls-redirect.md @@ -0,0 +1,5 @@ +--- +"react-native-app-auth": patch +--- + +Stop native OAuth endpoint redirects when custom headers are present so credential-bearing headers cannot be forwarded to another origin. diff --git a/docs/docs/usage/config.md b/docs/docs/usage/config.md index f1b9d5a0c..272069f9c 100644 --- a/docs/docs/usage/config.md +++ b/docs/docs/usage/config.md @@ -52,3 +52,7 @@ See specific example [configurations for your provider](/docs/category/providers - **androidAllowCustomBrowsers** - (`string[]`) (default: undefined) _ANDROID_ override the used browser for authorization. If no value is provided, all browsers are allowed. - **androidTrustedWebActivity** - (`boolean`) (default: `false`) _ANDROID_ Use [`EXTRA_LAUNCH_AS_TRUSTED_WEB_ACTIVITY`](https://developer.chrome.com/docs/android/trusted-web-activity/) when opening web view. - **connectionTimeoutSeconds** - (`number`) configure the request timeout interval in seconds. This must be a positive number. The default values are 60 seconds on iOS and 15 seconds on Android. + +Native discovery, token, and registration requests do not follow HTTP redirects when custom headers +are present. Configure the final endpoint URL directly so credential-bearing headers cannot be +forwarded to a redirected origin. diff --git a/packages/react-native-app-auth/android/src/main/java/com/rnappauth/utils/CustomConnectionBuilder.java b/packages/react-native-app-auth/android/src/main/java/com/rnappauth/utils/CustomConnectionBuilder.java index 734c12b83..e6eb7515d 100644 --- a/packages/react-native-app-auth/android/src/main/java/com/rnappauth/utils/CustomConnectionBuilder.java +++ b/packages/react-native-app-auth/android/src/main/java/com/rnappauth/utils/CustomConnectionBuilder.java @@ -57,7 +57,8 @@ public void setConnectionTimeout (int timeout) { public HttpURLConnection openConnection(@NonNull Uri uri) throws IOException { HttpURLConnection conn = connectionBuilder.openConnection(uri); - if (headers != null) { + if (headers != null && !headers.isEmpty()) { + conn.setInstanceFollowRedirects(false); for (Map.Entry header: headers.entrySet()) { conn.setRequestProperty(header.getKey(), header.getValue()); } diff --git a/packages/react-native-app-auth/ios/RNAppAuth.m b/packages/react-native-app-auth/ios/RNAppAuth.m index c48163427..f840d574b 100644 --- a/packages/react-native-app-auth/ios/RNAppAuth.m +++ b/packages/react-native-app-auth/ios/RNAppAuth.m @@ -8,7 +8,7 @@ #import #import "RNAppAuthAuthorizationFlowManager.h" -@interface RNAppAuth() { +@interface RNAppAuth() { id _currentSession; } @end @@ -554,10 +554,21 @@ - (void)configureUrlSession: (NSDictionary*) headers sessionTimeout: (double) se configuration.timeoutIntervalForRequest = sessionTimeout; - NSURLSession* session = [NSURLSession sessionWithConfiguration:configuration]; + NSURLSession* session = headers.count > 0 + ? [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil] + : [NSURLSession sessionWithConfiguration:configuration]; [OIDURLSessionProvider setSession:session]; } +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task +willPerformHTTPRedirection:(NSHTTPURLResponse *)response + newRequest:(NSURLRequest *)request + completionHandler:(void (^)(NSURLRequest *_Nullable))completionHandler +{ + completionHandler(nil); +} + /* * Take raw OIDAuthorizationResponse and turn it to response format to pass to JavaScript caller */