@@ -32,13 +32,33 @@ public final class FirebaseAI: Sendable {
3232 /// ``FirebaseApp``.
3333 /// - backend: The backend API for the Firebase AI SDK; if not specified, uses the default
3434 /// ``Backend/googleAI()`` (Gemini Developer API).
35+ /// - useLimitedUseAppCheckTokens: When sending tokens to the backend, this option enables
36+ /// the usage of App Check's limited-use tokens instead of the standard cached tokens.
37+ ///
38+ /// A new limited-use tokens will be generated for each request; providing a smaller attack
39+ /// surface for malicious parties to hijack tokens. When used alongside replay protection,
40+ /// limited-use tokens are also _consumed_ after each request, ensuring they can't be used
41+ /// again.
42+ ///
43+ /// _This flag is set to `false` by default._
44+ ///
45+ /// > Important: Replay protection is not currently supported for the FirebaseAI backend.
46+ /// > While this feature is being developed, you can still migrate to using
47+ /// > limited-use tokens. Because limited-use tokens are backwards compatible, you can still
48+ /// > use them without replay protection. Due to their shorter TTL over standard App Check
49+ /// > tokens, they still provide a security benefit.
50+ /// >
51+ /// > Migrating to limited-use tokens sooner minimizes disruption when support for replay
52+ /// > protection is added.
3553 /// - Returns: A `FirebaseAI` instance, configured with the custom `FirebaseApp`.
3654 public static func firebaseAI( app: FirebaseApp ? = nil ,
37- backend: Backend = . googleAI( ) ) -> FirebaseAI {
55+ backend: Backend = . googleAI( ) ,
56+ useLimitedUseAppCheckTokens: Bool = false ) -> FirebaseAI {
3857 let instance = createInstance (
3958 app: app,
4059 location: backend. location,
41- apiConfig: backend. apiConfig
60+ apiConfig: backend. apiConfig,
61+ useLimitedUseAppCheckTokens: useLimitedUseAppCheckTokens
4262 )
4363 // Verify that the `FirebaseAI` instance is always configured with the production endpoint since
4464 // this is the public API surface for creating an instance.
@@ -90,7 +110,8 @@ public final class FirebaseAI: Sendable {
90110 tools: tools,
91111 toolConfig: toolConfig,
92112 systemInstruction: systemInstruction,
93- requestOptions: requestOptions
113+ requestOptions: requestOptions,
114+ useLimitedUseAppCheckTokens: useLimitedUseAppCheckTokens
94115 )
95116 }
96117
@@ -126,7 +147,8 @@ public final class FirebaseAI: Sendable {
126147 apiConfig: apiConfig,
127148 generationConfig: generationConfig,
128149 safetySettings: safetySettings,
129- requestOptions: requestOptions
150+ requestOptions: requestOptions,
151+ useLimitedUseAppCheckTokens: useLimitedUseAppCheckTokens
130152 )
131153 }
132154
@@ -141,6 +163,8 @@ public final class FirebaseAI: Sendable {
141163
142164 let apiConfig : APIConfig
143165
166+ let useLimitedUseAppCheckTokens : Bool
167+
144168 /// A map of active `FirebaseAI` instances keyed by the `FirebaseApp` name and the `location`,
145169 /// in the format `appName:location`.
146170 private nonisolated ( unsafe) static var instances : [ InstanceKey : FirebaseAI ] = [ : ]
@@ -156,7 +180,8 @@ public final class FirebaseAI: Sendable {
156180 )
157181
158182 static func createInstance( app: FirebaseApp ? , location: String ? ,
159- apiConfig: APIConfig ) -> FirebaseAI {
183+ apiConfig: APIConfig ,
184+ useLimitedUseAppCheckTokens: Bool ) -> FirebaseAI {
160185 guard let app = app ?? FirebaseApp . app ( ) else {
161186 fatalError ( " No instance of the default Firebase app was found. " )
162187 }
@@ -166,16 +191,27 @@ public final class FirebaseAI: Sendable {
166191 // Unlock before the function returns.
167192 defer { os_unfair_lock_unlock ( & instancesLock) }
168193
169- let instanceKey = InstanceKey ( appName: app. name, location: location, apiConfig: apiConfig)
194+ let instanceKey = InstanceKey (
195+ appName: app. name,
196+ location: location,
197+ apiConfig: apiConfig,
198+ useLimitedUseAppCheckTokens: useLimitedUseAppCheckTokens
199+ )
170200 if let instance = instances [ instanceKey] {
171201 return instance
172202 }
173- let newInstance = FirebaseAI ( app: app, location: location, apiConfig: apiConfig)
203+ let newInstance = FirebaseAI (
204+ app: app,
205+ location: location,
206+ apiConfig: apiConfig,
207+ useLimitedUseAppCheckTokens: useLimitedUseAppCheckTokens
208+ )
174209 instances [ instanceKey] = newInstance
175210 return newInstance
176211 }
177212
178- init ( app: FirebaseApp , location: String ? , apiConfig: APIConfig ) {
213+ init ( app: FirebaseApp , location: String ? , apiConfig: APIConfig ,
214+ useLimitedUseAppCheckTokens: Bool ) {
179215 guard let projectID = app. options. projectID else {
180216 fatalError ( " The Firebase app named \" \( app. name) \" has no project ID in its configuration. " )
181217 }
@@ -195,6 +231,7 @@ public final class FirebaseAI: Sendable {
195231 )
196232 self . apiConfig = apiConfig
197233 self . location = location
234+ self . useLimitedUseAppCheckTokens = useLimitedUseAppCheckTokens
198235 }
199236
200237 func modelResourceName( modelName: String ) -> String {
@@ -249,5 +286,6 @@ public final class FirebaseAI: Sendable {
249286 let appName : String
250287 let location : String ?
251288 let apiConfig : APIConfig
289+ let useLimitedUseAppCheckTokens : Bool
252290 }
253291}
0 commit comments