Description
Expected behavior: When calling getDownloadURL() on a storage reference created from a named (non-default) Firebase app, the request should include the Authorization header from that app's authenticated user.
Actual behavior: The request is sent without an Authorization header, resulting in StorageErrorCode.unauthorized. This happens because the InstanceCache in Storage.swift caches Storage instances keyed by bucket name only, ignoring the FirebaseApp. When a named app shares the same storage bucket as the [DEFAULT] app, the cached [DEFAULT] instance is returned — carrying the wrong (or empty) AuthInterop.
Reproducing the issue
-
Have a GoogleService-Info.plist that creates a [DEFAULT] app for project my-project with storageBucket: "my-project.appspot.com". Do not sign in on the default app.
-
Dynamically initialize a named app pointing to the same project:
let options = FirebaseOptions(/* same project credentials */)
options.storageBucket = "my-project.appspot.com"
FirebaseApp.configure(name: "my-named-app", options: options)
- Sign in on the named app:
Auth.auth(app: FirebaseApp.app(name: "my-named-app")!).signIn(withCustomToken: token)
-
Confirm auth works — Auth.auth(app:).currentUser is non-null with correct claims.
-
Attempt to get a download URL via the named app:
let storage = Storage.storage(app: FirebaseApp.app(name: "my-named-app")!, url: "gs://my-project.appspot.com")
let ref = storage.reference(withPath: "some/file.png")
ref.downloadURL { url, error in
// error: StorageErrorCode.unauthorized
}
- The same request succeeds when made manually via
URLSession with an explicit Authorization: Bearer <token> header.
Firebase SDK Version
11.x (current main branch)
Xcode Version
26.x
Installation Method
CocoaPods
Firebase Product(s)
Storage
Targeted Platforms
iOS
Relevant Log Output
If using Swift Package Manager, the project's Package.resolved
Expand Package.resolved snippet
Replace this line with the contents of your Package.resolved.
If using CocoaPods, the project's Podfile.lock
Expand Podfile.lock snippet
Replace this line with the contents of your Podfile.lock!
Description
Expected behavior: When calling
getDownloadURL()on a storage reference created from a named (non-default) Firebase app, the request should include theAuthorizationheader from that app's authenticated user.Actual behavior: The request is sent without an
Authorizationheader, resulting inStorageErrorCode.unauthorized. This happens because theInstanceCacheinStorage.swiftcachesStorageinstances keyed by bucket name only, ignoring theFirebaseApp. When a named app shares the same storage bucket as the[DEFAULT]app, the cached[DEFAULT]instance is returned — carrying the wrong (or empty)AuthInterop.Reproducing the issue
Have a
GoogleService-Info.plistthat creates a[DEFAULT]app for projectmy-projectwithstorageBucket: "my-project.appspot.com". Do not sign in on the default app.Dynamically initialize a named app pointing to the same project:
Confirm auth works —
Auth.auth(app:).currentUseris non-null with correct claims.Attempt to get a download URL via the named app:
URLSessionwith an explicitAuthorization: Bearer <token>header.Firebase SDK Version
11.x (current main branch)
Xcode Version
26.x
Installation Method
CocoaPods
Firebase Product(s)
Storage
Targeted Platforms
iOS
Relevant Log Output
If using Swift Package Manager, the project's Package.resolved
Expand
Package.resolvedsnippetReplace this line with the contents of your Package.resolved.If using CocoaPods, the project's Podfile.lock
Expand
Podfile.locksnippetReplace this line with the contents of your Podfile.lock!