From 55aea3a04a7b0b425cb7e93449f17a966303badb Mon Sep 17 00:00:00 2001 From: Daymon Date: Wed, 20 Aug 2025 12:00:35 -0500 Subject: [PATCH 01/11] Move useLimitedUseTokens to FirebaseInfo --- FirebaseAI/Sources/FirebaseAI.swift | 12 ++++-------- FirebaseAI/Sources/FirebaseInfo.swift | 5 ++++- FirebaseAI/Sources/GenerativeAIService.swift | 9 +++------ FirebaseAI/Sources/GenerativeModel.swift | 8 ++------ .../Sources/Types/Public/Imagen/ImagenModel.swift | 6 ++---- FirebaseAI/Tests/Unit/ChatTests.swift | 3 ++- .../Tests/Unit/GenerativeModelVertexAITests.swift | 4 ++-- .../Unit/TestUtilities/GenerativeModelTestUtil.swift | 6 ++++-- 8 files changed, 23 insertions(+), 30 deletions(-) diff --git a/FirebaseAI/Sources/FirebaseAI.swift b/FirebaseAI/Sources/FirebaseAI.swift index d4c2e9d545d..da954ab7b28 100644 --- a/FirebaseAI/Sources/FirebaseAI.swift +++ b/FirebaseAI/Sources/FirebaseAI.swift @@ -110,8 +110,7 @@ public final class FirebaseAI: Sendable { tools: tools, toolConfig: toolConfig, systemInstruction: systemInstruction, - requestOptions: requestOptions, - useLimitedUseAppCheckTokens: useLimitedUseAppCheckTokens + requestOptions: requestOptions ) } @@ -147,8 +146,7 @@ public final class FirebaseAI: Sendable { apiConfig: apiConfig, generationConfig: generationConfig, safetySettings: safetySettings, - requestOptions: requestOptions, - useLimitedUseAppCheckTokens: useLimitedUseAppCheckTokens + requestOptions: requestOptions ) } @@ -163,8 +161,6 @@ public final class FirebaseAI: Sendable { let apiConfig: APIConfig - let useLimitedUseAppCheckTokens: Bool - /// A map of active `FirebaseAI` instances keyed by the `FirebaseApp` name and the `location`, /// in the format `appName:location`. private nonisolated(unsafe) static var instances: [InstanceKey: FirebaseAI] = [:] @@ -227,11 +223,11 @@ public final class FirebaseAI: Sendable { projectID: projectID, apiKey: apiKey, firebaseAppID: app.options.googleAppID, - firebaseApp: app + firebaseApp: app, + useLimitedUseAppCheckTokens: useLimitedUseAppCheckTokens ) self.apiConfig = apiConfig self.location = location - self.useLimitedUseAppCheckTokens = useLimitedUseAppCheckTokens } func modelResourceName(modelName: String) -> String { diff --git a/FirebaseAI/Sources/FirebaseInfo.swift b/FirebaseAI/Sources/FirebaseInfo.swift index c1f27aa7fe3..6b10dec4e5f 100644 --- a/FirebaseAI/Sources/FirebaseInfo.swift +++ b/FirebaseAI/Sources/FirebaseInfo.swift @@ -27,6 +27,7 @@ struct FirebaseInfo: Sendable { let projectID: String let apiKey: String let firebaseAppID: String + let useLimitedUseAppCheckTokens: Bool let app: FirebaseApp init(appCheck: AppCheckInterop? = nil, @@ -34,12 +35,14 @@ struct FirebaseInfo: Sendable { projectID: String, apiKey: String, firebaseAppID: String, - firebaseApp: FirebaseApp) { + firebaseApp: FirebaseApp, + useLimitedUseAppCheckTokens: Bool) { self.appCheck = appCheck self.auth = auth self.projectID = projectID self.apiKey = apiKey self.firebaseAppID = firebaseAppID + self.useLimitedUseAppCheckTokens = useLimitedUseAppCheckTokens app = firebaseApp } } diff --git a/FirebaseAI/Sources/GenerativeAIService.swift b/FirebaseAI/Sources/GenerativeAIService.swift index 5b676162c94..c50be44a7c0 100644 --- a/FirebaseAI/Sources/GenerativeAIService.swift +++ b/FirebaseAI/Sources/GenerativeAIService.swift @@ -30,12 +30,9 @@ struct GenerativeAIService { private let urlSession: URLSession - private let useLimitedUseAppCheckTokens: Bool - - init(firebaseInfo: FirebaseInfo, urlSession: URLSession, useLimitedUseAppCheckTokens: Bool) { + init(firebaseInfo: FirebaseInfo, urlSession: URLSession) { self.firebaseInfo = firebaseInfo self.urlSession = urlSession - self.useLimitedUseAppCheckTokens = useLimitedUseAppCheckTokens } func loadRequest(request: T) async throws -> T.Response { @@ -212,7 +209,7 @@ struct GenerativeAIService { private func fetchAppCheckToken(appCheck: AppCheckInterop) async throws -> FIRAppCheckTokenResultInterop { - if useLimitedUseAppCheckTokens { + if firebaseInfo.useLimitedUseAppCheckTokens { if let token = await getLimitedUseAppCheckToken(appCheck: appCheck) { return token } @@ -242,7 +239,7 @@ struct GenerativeAIService { Never >) in guard - useLimitedUseAppCheckTokens, + firebaseInfo.useLimitedUseAppCheckTokens, // `getLimitedUseToken(completion:)` is an optional protocol method. Optional binding // is performed to make sure `continuation` is called even if the method’s not implemented. let limitedUseTokenClosure = appCheck.getLimitedUseToken diff --git a/FirebaseAI/Sources/GenerativeModel.swift b/FirebaseAI/Sources/GenerativeModel.swift index 2807022de59..8d3f5e043a7 100644 --- a/FirebaseAI/Sources/GenerativeModel.swift +++ b/FirebaseAI/Sources/GenerativeModel.swift @@ -76,8 +76,6 @@ public final class GenerativeModel: Sendable { /// only text content is supported. /// - requestOptions: Configuration parameters for sending requests to the backend. /// - urlSession: The `URLSession` to use for requests; defaults to `URLSession.shared`. - /// - useLimitedUseAppCheckTokens: Use App Check's limited-use tokens instead of the standard - /// cached tokens. init(modelName: String, modelResourceName: String, firebaseInfo: FirebaseInfo, @@ -88,15 +86,13 @@ public final class GenerativeModel: Sendable { toolConfig: ToolConfig? = nil, systemInstruction: ModelContent? = nil, requestOptions: RequestOptions, - urlSession: URLSession = GenAIURLSession.default, - useLimitedUseAppCheckTokens: Bool = false) { + urlSession: URLSession = GenAIURLSession.default) { self.modelName = modelName self.modelResourceName = modelResourceName self.apiConfig = apiConfig generativeAIService = GenerativeAIService( firebaseInfo: firebaseInfo, - urlSession: urlSession, - useLimitedUseAppCheckTokens: useLimitedUseAppCheckTokens + urlSession: urlSession ) self.generationConfig = generationConfig self.safetySettings = safetySettings diff --git a/FirebaseAI/Sources/Types/Public/Imagen/ImagenModel.swift b/FirebaseAI/Sources/Types/Public/Imagen/ImagenModel.swift index 542f842362c..729fad9f28d 100644 --- a/FirebaseAI/Sources/Types/Public/Imagen/ImagenModel.swift +++ b/FirebaseAI/Sources/Types/Public/Imagen/ImagenModel.swift @@ -53,14 +53,12 @@ public final class ImagenModel { generationConfig: ImagenGenerationConfig?, safetySettings: ImagenSafetySettings?, requestOptions: RequestOptions, - urlSession: URLSession = GenAIURLSession.default, - useLimitedUseAppCheckTokens: Bool = false) { + urlSession: URLSession = GenAIURLSession.default) { self.modelResourceName = modelResourceName self.apiConfig = apiConfig generativeAIService = GenerativeAIService( firebaseInfo: firebaseInfo, - urlSession: urlSession, - useLimitedUseAppCheckTokens: useLimitedUseAppCheckTokens + urlSession: urlSession ) self.generationConfig = generationConfig self.safetySettings = safetySettings diff --git a/FirebaseAI/Tests/Unit/ChatTests.swift b/FirebaseAI/Tests/Unit/ChatTests.swift index 4bf89f8cb51..7ecebf42e28 100644 --- a/FirebaseAI/Tests/Unit/ChatTests.swift +++ b/FirebaseAI/Tests/Unit/ChatTests.swift @@ -68,7 +68,8 @@ final class ChatTests: XCTestCase { projectID: "my-project-id", apiKey: "API_KEY", firebaseAppID: "My app ID", - firebaseApp: app + firebaseApp: app, + useLimitedUseAppCheckTokens: false ), apiConfig: FirebaseAI.defaultVertexAIAPIConfig, tools: nil, diff --git a/FirebaseAI/Tests/Unit/GenerativeModelVertexAITests.swift b/FirebaseAI/Tests/Unit/GenerativeModelVertexAITests.swift index 80a383eb461..94589577568 100644 --- a/FirebaseAI/Tests/Unit/GenerativeModelVertexAITests.swift +++ b/FirebaseAI/Tests/Unit/GenerativeModelVertexAITests.swift @@ -507,13 +507,13 @@ final class GenerativeModelVertexAITests: XCTestCase { modelName: testModelName, modelResourceName: testModelResourceName, firebaseInfo: GenerativeModelTestUtil.testFirebaseInfo( - appCheck: AppCheckInteropFake(token: appCheckToken) + appCheck: AppCheckInteropFake(token: appCheckToken), + useLimitedUseAppCheckTokens: true ), apiConfig: apiConfig, tools: nil, requestOptions: RequestOptions(), urlSession: urlSession, - useLimitedUseAppCheckTokens: true ) MockURLProtocol .requestHandler = try GenerativeModelTestUtil.httpRequestHandler( diff --git a/FirebaseAI/Tests/Unit/TestUtilities/GenerativeModelTestUtil.swift b/FirebaseAI/Tests/Unit/TestUtilities/GenerativeModelTestUtil.swift index 9b00f0b0c87..ee4f47bc5b0 100644 --- a/FirebaseAI/Tests/Unit/TestUtilities/GenerativeModelTestUtil.swift +++ b/FirebaseAI/Tests/Unit/TestUtilities/GenerativeModelTestUtil.swift @@ -103,7 +103,8 @@ enum GenerativeModelTestUtil { static func testFirebaseInfo(appCheck: AppCheckInterop? = nil, auth: AuthInterop? = nil, - privateAppID: Bool = false) -> FirebaseInfo { + privateAppID: Bool = false, + useLimitedUseAppCheckTokens: Bool = false) -> FirebaseInfo { let app = FirebaseApp(instanceWithName: "testApp", options: FirebaseOptions(googleAppID: "ignore", gcmSenderID: "ignore")) @@ -114,7 +115,8 @@ enum GenerativeModelTestUtil { projectID: "my-project-id", apiKey: "API_KEY", firebaseAppID: "My app ID", - firebaseApp: app + firebaseApp: app, + useLimitedUseAppCheckTokens: useLimitedUseAppCheckTokens ) } } From 18a2ee5376efbf19b3a0cc0a61ec12b77c9ae680 Mon Sep 17 00:00:00 2001 From: Daymon Date: Wed, 20 Aug 2025 12:01:35 -0500 Subject: [PATCH 02/11] formatting --- FirebaseAI/Sources/GenerativeAIService.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FirebaseAI/Sources/GenerativeAIService.swift b/FirebaseAI/Sources/GenerativeAIService.swift index c50be44a7c0..8056d4172b8 100644 --- a/FirebaseAI/Sources/GenerativeAIService.swift +++ b/FirebaseAI/Sources/GenerativeAIService.swift @@ -209,7 +209,7 @@ struct GenerativeAIService { private func fetchAppCheckToken(appCheck: AppCheckInterop) async throws -> FIRAppCheckTokenResultInterop { - if firebaseInfo.useLimitedUseAppCheckTokens { + if firebaseInfo.useLimitedUseAppCheckTokens { if let token = await getLimitedUseAppCheckToken(appCheck: appCheck) { return token } From 8565d10504781d709eaa222d46b2099ea194c01c Mon Sep 17 00:00:00 2001 From: Daymon Date: Mon, 25 Aug 2025 10:34:33 -0500 Subject: [PATCH 03/11] Update CHANGELOG.md --- FirebaseAI/CHANGELOG.md | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/FirebaseAI/CHANGELOG.md b/FirebaseAI/CHANGELOG.md index b5f3199a797..d177fd93261 100644 --- a/FirebaseAI/CHANGELOG.md +++ b/FirebaseAI/CHANGELOG.md @@ -1,13 +1,10 @@ # 12.2.0 - [feature] Added support for returning thought summaries, which are synthesized versions of a model's internal reasoning process. (#15096) -- [feature] Added a new configuration option to use limited-use App - Check tokens for attesting Firebase AI Logic requests. This enhances - security against replay attacks. To use this feature, configure it - explicitly via the new `useLimitedUseAppCheckTokens` parameter when - initializing `FirebaseAI`. We recommend migrating to limited-use - tokens now, so your app will be ready to take advantage of replay - protection when it becomes available for Firebase AI Logic. (#15099) +- [feature] Added support for limited-use tokens with Firebase App Check. These short-lived tokens + provide greater protection for the APIs that give you access to Gemini and Imagen models. Learn + how to [enable usage of limited-use tokens](https://firebase.google.com/docs/ai-logic/app-check). + (#15099) # 12.0.0 - [feature] Added support for Grounding with Google Search. (#15014) From c6a4e79d5c95d2792d0135f481929222fe6f5a03 Mon Sep 17 00:00:00 2001 From: Daymon Date: Mon, 25 Aug 2025 10:35:16 -0500 Subject: [PATCH 04/11] Update docs to point to web page --- FirebaseAI/Sources/FirebaseAI.swift | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/FirebaseAI/Sources/FirebaseAI.swift b/FirebaseAI/Sources/FirebaseAI.swift index da954ab7b28..034fa6b8f8f 100644 --- a/FirebaseAI/Sources/FirebaseAI.swift +++ b/FirebaseAI/Sources/FirebaseAI.swift @@ -33,12 +33,8 @@ public final class FirebaseAI: Sendable { /// - backend: The backend API for the Firebase AI SDK; if not specified, uses the default /// ``Backend/googleAI()`` (Gemini Developer API). /// - useLimitedUseAppCheckTokens: When sending tokens to the backend, this option enables - /// the usage of App Check's limited-use tokens instead of the standard cached tokens. - /// - /// A new limited-use tokens will be generated for each request; providing a smaller attack - /// surface for malicious parties to hijack tokens. When used alongside replay protection, - /// limited-use tokens are also _consumed_ after each request, ensuring they can't be used - /// again. + /// the usage of App Check's limited-use tokens instead of the standard cached tokens. To learn more, see the docs for + /// [App Check in Firebase AI Logic](https://firebase.google.com/docs/ai-logic/app-check). /// /// _This flag is set to `false` by default._ /// From a2419665e99881fe10e80508b5f89c7a9686ebb2 Mon Sep 17 00:00:00 2001 From: Daymon Date: Mon, 25 Aug 2025 10:36:24 -0500 Subject: [PATCH 05/11] lint --- FirebaseAI/Sources/FirebaseAI.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/FirebaseAI/Sources/FirebaseAI.swift b/FirebaseAI/Sources/FirebaseAI.swift index 034fa6b8f8f..ec1df980444 100644 --- a/FirebaseAI/Sources/FirebaseAI.swift +++ b/FirebaseAI/Sources/FirebaseAI.swift @@ -33,7 +33,8 @@ public final class FirebaseAI: Sendable { /// - backend: The backend API for the Firebase AI SDK; if not specified, uses the default /// ``Backend/googleAI()`` (Gemini Developer API). /// - useLimitedUseAppCheckTokens: When sending tokens to the backend, this option enables - /// the usage of App Check's limited-use tokens instead of the standard cached tokens. To learn more, see the docs for + /// the usage of App Check's limited-use tokens instead of the standard cached tokens. To + /// learn more, see the docs for /// [App Check in Firebase AI Logic](https://firebase.google.com/docs/ai-logic/app-check). /// /// _This flag is set to `false` by default._ From 04675d6d80e9dd4a4e35a0c4b4d30d4142fdd78e Mon Sep 17 00:00:00 2001 From: Daymon Date: Mon, 25 Aug 2025 10:36:38 -0500 Subject: [PATCH 06/11] Update CHANGELOG.md --- FirebaseAI/CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/FirebaseAI/CHANGELOG.md b/FirebaseAI/CHANGELOG.md index d177fd93261..1cc90f6028e 100644 --- a/FirebaseAI/CHANGELOG.md +++ b/FirebaseAI/CHANGELOG.md @@ -1,8 +1,8 @@ # 12.2.0 - [feature] Added support for returning thought summaries, which are synthesized versions of a model's internal reasoning process. (#15096) -- [feature] Added support for limited-use tokens with Firebase App Check. These short-lived tokens - provide greater protection for the APIs that give you access to Gemini and Imagen models. Learn +- [feature] Added support for limited-use tokens with Firebase App Check. These short-lived tokens + provide greater protection for the APIs that give you access to Gemini and Imagen models. Learn how to [enable usage of limited-use tokens](https://firebase.google.com/docs/ai-logic/app-check). (#15099) From 9fbf6e6bcaa3b71e0ad69803b3216a3383b3a0c2 Mon Sep 17 00:00:00 2001 From: Daymon Date: Mon, 25 Aug 2025 10:39:30 -0500 Subject: [PATCH 07/11] Remove mention of replay protection --- FirebaseAI/Sources/FirebaseAI.swift | 7 ------- 1 file changed, 7 deletions(-) diff --git a/FirebaseAI/Sources/FirebaseAI.swift b/FirebaseAI/Sources/FirebaseAI.swift index ec1df980444..73d8efe2bce 100644 --- a/FirebaseAI/Sources/FirebaseAI.swift +++ b/FirebaseAI/Sources/FirebaseAI.swift @@ -38,13 +38,6 @@ public final class FirebaseAI: Sendable { /// [App Check in Firebase AI Logic](https://firebase.google.com/docs/ai-logic/app-check). /// /// _This flag is set to `false` by default._ - /// - /// > Important: Replay protection is not currently supported for the FirebaseAI backend. - /// > While this feature is being developed, you can still migrate to using - /// > limited-use tokens. Because limited-use tokens are backwards compatible, you can still - /// > use them without replay protection. Due to their shorter TTL over standard App Check - /// > tokens, they still provide a security benefit. - /// > /// > Migrating to limited-use tokens sooner minimizes disruption when support for replay /// > protection is added. /// - Returns: A `FirebaseAI` instance, configured with the custom `FirebaseApp`. From c86c77fbc3841bb44b14bc4c638b55405d061813 Mon Sep 17 00:00:00 2001 From: Daymon Date: Mon, 25 Aug 2025 10:50:23 -0500 Subject: [PATCH 08/11] Update FirebaseAI.swift --- FirebaseAI/Sources/FirebaseAI.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/FirebaseAI/Sources/FirebaseAI.swift b/FirebaseAI/Sources/FirebaseAI.swift index 73d8efe2bce..05996d9a2f6 100644 --- a/FirebaseAI/Sources/FirebaseAI.swift +++ b/FirebaseAI/Sources/FirebaseAI.swift @@ -33,9 +33,9 @@ public final class FirebaseAI: Sendable { /// - backend: The backend API for the Firebase AI SDK; if not specified, uses the default /// ``Backend/googleAI()`` (Gemini Developer API). /// - useLimitedUseAppCheckTokens: When sending tokens to the backend, this option enables - /// the usage of App Check's limited-use tokens instead of the standard cached tokens. To - /// learn more, see the docs for - /// [App Check in Firebase AI Logic](https://firebase.google.com/docs/ai-logic/app-check). + /// the usage of App Check's limited-use tokens instead of the standard cached tokens. Learn more about + /// [limited-use tokens](https://firebase.google.com/docs/ai-logic/app-check), including + /// their nuances, when to use them, and best practices for integrating them into your app. /// /// _This flag is set to `false` by default._ /// > Migrating to limited-use tokens sooner minimizes disruption when support for replay From ccfaec59e685322406626359efa232d8ecbb38e9 Mon Sep 17 00:00:00 2001 From: Daymon Date: Mon, 25 Aug 2025 10:51:55 -0500 Subject: [PATCH 09/11] Update FirebaseAI.swift --- FirebaseAI/Sources/FirebaseAI.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/FirebaseAI/Sources/FirebaseAI.swift b/FirebaseAI/Sources/FirebaseAI.swift index 05996d9a2f6..b8553c1725e 100644 --- a/FirebaseAI/Sources/FirebaseAI.swift +++ b/FirebaseAI/Sources/FirebaseAI.swift @@ -33,7 +33,8 @@ public final class FirebaseAI: Sendable { /// - backend: The backend API for the Firebase AI SDK; if not specified, uses the default /// ``Backend/googleAI()`` (Gemini Developer API). /// - useLimitedUseAppCheckTokens: When sending tokens to the backend, this option enables - /// the usage of App Check's limited-use tokens instead of the standard cached tokens. Learn more about + /// the usage of App Check's limited-use tokens instead of the standard cached tokens. Learn + /// more about /// [limited-use tokens](https://firebase.google.com/docs/ai-logic/app-check), including /// their nuances, when to use them, and best practices for integrating them into your app. /// From 880b81fac5b5ad6013cd170336908a8d63f9d841 Mon Sep 17 00:00:00 2001 From: Daymon Date: Mon, 25 Aug 2025 11:32:06 -0500 Subject: [PATCH 10/11] Update GenerativeModelVertexAITests.swift --- FirebaseAI/Tests/Unit/GenerativeModelVertexAITests.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FirebaseAI/Tests/Unit/GenerativeModelVertexAITests.swift b/FirebaseAI/Tests/Unit/GenerativeModelVertexAITests.swift index 94589577568..0e33ba557e6 100644 --- a/FirebaseAI/Tests/Unit/GenerativeModelVertexAITests.swift +++ b/FirebaseAI/Tests/Unit/GenerativeModelVertexAITests.swift @@ -513,7 +513,7 @@ final class GenerativeModelVertexAITests: XCTestCase { apiConfig: apiConfig, tools: nil, requestOptions: RequestOptions(), - urlSession: urlSession, + urlSession: urlSession ) MockURLProtocol .requestHandler = try GenerativeModelTestUtil.httpRequestHandler( From b08814faacfe97cdb7e6ab9b942a18f0e7bf2355 Mon Sep 17 00:00:00 2001 From: Daymon Date: Mon, 25 Aug 2025 13:15:37 -0500 Subject: [PATCH 11/11] Fix indent --- FirebaseAI/Sources/FirebaseAI.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/FirebaseAI/Sources/FirebaseAI.swift b/FirebaseAI/Sources/FirebaseAI.swift index b8553c1725e..7cb33e30a33 100644 --- a/FirebaseAI/Sources/FirebaseAI.swift +++ b/FirebaseAI/Sources/FirebaseAI.swift @@ -34,9 +34,9 @@ public final class FirebaseAI: Sendable { /// ``Backend/googleAI()`` (Gemini Developer API). /// - useLimitedUseAppCheckTokens: When sending tokens to the backend, this option enables /// the usage of App Check's limited-use tokens instead of the standard cached tokens. Learn - /// more about - /// [limited-use tokens](https://firebase.google.com/docs/ai-logic/app-check), including - /// their nuances, when to use them, and best practices for integrating them into your app. + /// more about [limited-use tokens](https://firebase.google.com/docs/ai-logic/app-check), + /// including their nuances, when to use them, and best practices for integrating them into + /// your app. /// /// _This flag is set to `false` by default._ /// > Migrating to limited-use tokens sooner minimizes disruption when support for replay