Skip to content

🔥 [storage] getDownloadURL does not attach Authorization header for dynamically-initialized named Firebase apps #8958

@llamington

Description

@llamington

Issue

When using @react-native-firebase/storage with a Firebase app that was initialized dynamically via initializeApp(options, appName) in JavaScript (rather than using the [DEFAULT] app from a natively-bundled google-services.json / GoogleService-Info.plist), calls to getDownloadURL() fail with [storage/unauthorized] because the native module does not attach the Authorization header to the outgoing HTTP request.

Reproduction

  1. Initialize a named Firebase app dynamically:
const app = await initializeApp({
  appId: "...",
  projectId: "my-project",
  apiKey: "...",
  storageBucket: "my-project.appspot.com",
  // ...
}, "my-named-app");
  1. Sign in with a custom token on that named app:
await signInWithCustomToken(getAuth(app), customToken);
  1. Confirm auth works — getAuth(app).currentUser is non-null with correct claims including the custom claims required by storage security rules.

  2. Attempt to get a download URL:

// All of these fail with [storage/unauthorized]:

// Namespace API:
await storage(app).refFromURL("gs://my-project.appspot.com/some/file.png").getDownloadURL();

// Method on app:
await (app as any).storage().refFromURL("gs://my-project.appspot.com/some/file.png").getDownloadURL();

// Modular API:
await getDownloadURL(refFromURL(storage(app), "gs://my-project.appspot.com/some/file.png"));

// Default app (which has no signed-in user):
await storage().refFromURL("gs://my-project.appspot.com/some/file.png").getDownloadURL();
  1. The same request succeeds when made manually via fetch with an explicit Authorization: Bearer header using the token from getAuth(app).currentUser.getIdToken():
const token = await getAuth(app).currentUser.getIdToken();
const encodedPath = encodeURIComponent("some/file.png");
const url = `https://firebasestorage.googleapis.com/v0/b/my-project.appspot.com/o/${encodedPath}?alt=media`;
const response = await fetch(url, {
  headers: { Authorization: `Bearer ${token}` },
});
// response.status === 200

Diagnosis

Using Proxyman to inspect network traffic from the iOS simulator, we confirmed:

  • The manual fetch call includes the Authorization: Bearer <token> header and succeeds (200)
  • The native storage SDK request does not include the Authorization header and fails (403)

The [DEFAULT] Firebase app (created from the natively-bundled google-services.json) points to the same Firebase project but has no signed-in user. The storage module appears to either not resolve the auth token for named apps, or falls back to the [DEFAULT] app's (empty) auth state when constructing the native request.

Additional context

  • The natively-bundled google-services.json / GoogleService-Info.plist points to the same Firebase project — the [DEFAULT] app exists but has no signed-in user
  • The named app is created at runtime during a device pairing flow, which is why we cannot use the [DEFAULT] app
  • refFromURL() succeeds and correctly resolves the bucket and full path — only getDownloadURL() fails
  • Tested on iOS simulator

Workaround

Bypass the storage SDK entirely and use the Firebase Storage REST API with an explicit bearer token:

const token = await getAuth(app).currentUser.getIdToken();
const encodedPath = encodeURIComponent(storagePath);
const url = `https://firebasestorage.googleapis.com/v0/b/${bucket}/o/${encodedPath}?alt=media`;
const response = await fetch(url, {
  headers: { Authorization: `Bearer ${token}` },
});

Project Files

Javascript

Click To Expand

package.json:

{
  "@react-native-firebase/app": "^23.7.0",
  "@react-native-firebase/auth": "^23.7.0",
  "@react-native-firebase/firestore": "^23.7.0",
  "@react-native-firebase/messaging": "^23.7.0",
  "@react-native-firebase/storage": "^23.7.0"
}

firebase.json for react-native-firebase v6:

# N/A

iOS

Click To Expand

ios/Podfile:

  • I'm not using Pods
  • I'm using Pods and my Podfile looks like:
# Managed by Expo — standard Expo SDK 53 Podfile

AppDelegate.m:

// Managed by Expo


Android

Click To Expand

Have you converted to AndroidX?

  • my application is an AndroidX application?
  • I am using android/gradle.settings jetifier=true for Android compatibility?
  • I am using the NPM package jetifier for react-native compatibility?

android/build.gradle:

// Managed by Expo

android/app/build.gradle:

// Managed by Expo

android/settings.gradle:

// Managed by Expo

MainApplication.java:

// Managed by Expo

AndroidManifest.xml:

<!-- Managed by Expo -->


Environment

Click To Expand

react-native info output:

React Native (Expo SDK 53, New Architecture enabled)
iOS Simulator
  • Platform that you're experiencing the issue on:
    • iOS
    • Android
    • iOS but have not tested behavior on Android
    • Android but have not tested behavior on iOS
    • Both
  • react-native-firebase version you're using that has this issue:
    • @react-native-firebase/storage@23.7.0
  • Firebase module(s) you're using that has the issue:
    • Storage
  • Are you using TypeScript?
    • Yes, TypeScript 5.x

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions