Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions FirebaseAI/Sources/Types/Internal/AppCheck.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ extension AppCheckInterop {
/// - domain: A string dictating where this method is being called from. Used in any thrown
/// errors, to avoid hard-to-parse traces.
func fetchAppCheckToken(limitedUse: Bool,
domain: String) async throws -> FIRAppCheckTokenResultInterop {
domain: String) async throws -> (token: String, error: Error?) {
if limitedUse {
if let token = await getLimitedUseTokenAsync() {
return token
Expand All @@ -47,14 +47,18 @@ extension AppCheckInterop {
#endif
}

return await getToken(forcingRefresh: false)
return await withCheckedContinuation { continuation in
self.getToken(forcingRefresh: false) { result in
continuation.resume(returning: (token: result.token, error: result.error))
}
}
}

private func getLimitedUseTokenAsync() async
-> FIRAppCheckTokenResultInterop? {
-> (token: String, error: Error?)? {
// At the moment, `await` doesn’t get along with Objective-C’s optional protocol methods.
await withCheckedContinuation { (continuation: CheckedContinuation<
FIRAppCheckTokenResultInterop?,
(token: String, error: Error?)?,
Never
>) in
guard
Expand All @@ -67,7 +71,7 @@ extension AppCheckInterop {

limitedUseTokenClosure { tokenResult in
// The placeholder token should be used in the case of App Check error.
continuation.resume(returning: tokenResult)
continuation.resume(returning: (token: tokenResult.token, error: tokenResult.error))
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions FirebaseAuth/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
# Unreleased
- [fixed] Fixed a persistent crash when interacting with App Check under some
Swift toolchains (like the Flutter SDK) by avoiding a compiler bug in Swift
concurrency thunk generation. (#16549)
- [fixed] Fixed an issue on iOS 15+ where users were randomly logged out during
prewarming while the device was locked. (#16498)

Expand Down
27 changes: 27 additions & 0 deletions FirebaseAuth/Sources/Swift/Auth/AppCheckInterop+FirebaseAuth.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright 2026 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import Foundation

@preconcurrency import FirebaseAppCheckInterop

extension AppCheckInterop {
func getTokenResult(forcingRefresh: Bool) async -> (token: String, error: Error?) {
await withCheckedContinuation { continuation in
self.getToken(forcingRefresh: forcingRefresh) { result in
continuation.resume(returning: (token: result.token, error: result.error))
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -435,7 +435,7 @@ import Foundation
}

if let appCheck {
let tokenResult = await appCheck.getToken(forcingRefresh: false)
let tokenResult = await appCheck.getTokenResult(forcingRefresh: false)
if let error = tokenResult.error {
AuthLog.logWarning(code: "I-AUT000018",
message: "Error getting App Check token; using placeholder " +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -641,7 +641,7 @@ import Foundation
components?.queryItems = queryItems

if let appCheck {
let tokenResult = await appCheck.getToken(forcingRefresh: false)
let tokenResult = await appCheck.getTokenResult(forcingRefresh: false)
if let error = tokenResult.error {
AuthLog.logWarning(code: "I-AUT000018",
message: "Error getting App Check token; using placeholder " +
Expand Down
2 changes: 1 addition & 1 deletion FirebaseAuth/Sources/Swift/Backend/AuthBackend.swift
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ final class AuthBackend: AuthBackendProtocol {
await requestConfiguration.heartbeatLogger?.asyncHeaderValue()
}
let appCheckTokenHeaderValue = Task {
await requestConfiguration.appCheck?.getToken(forcingRefresh: false)
await requestConfiguration.appCheck?.getTokenResult(forcingRefresh: false)
}

return await withTaskCancellationHandler {
Expand Down
13 changes: 7 additions & 6 deletions FirebaseFunctions/Sources/Internal/FunctionsContext.swift
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,13 @@ struct FunctionsContextProvider: Sendable {
}

private func getAppCheckToken(options: HTTPSCallableOptions?) async -> String? {
guard
options?.requireLimitedUseAppCheckTokens != true,
let tokenResult = await appCheck?.getToken(forcingRefresh: false)
else { return nil }
// The placeholder token should be used in the case of App Check error.
return tokenResult.token
guard options?.requireLimitedUseAppCheckTokens != true, let appCheck else { return nil }

return await withCheckedContinuation { continuation in
appCheck.getToken(forcingRefresh: false) { result in
continuation.resume(returning: result.token)
}
}
}

private func getLimitedUseAppCheckToken(options: HTTPSCallableOptions?) async -> String? {
Expand Down
Loading