@@ -32,13 +32,33 @@ public final class FirebaseAI: Sendable {
32
32
/// ``FirebaseApp``.
33
33
/// - backend: The backend API for the Firebase AI SDK; if not specified, uses the default
34
34
/// ``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.
35
53
/// - Returns: A `FirebaseAI` instance, configured with the custom `FirebaseApp`.
36
54
public static func firebaseAI( app: FirebaseApp ? = nil ,
37
- backend: Backend = . googleAI( ) ) -> FirebaseAI {
55
+ backend: Backend = . googleAI( ) ,
56
+ useLimitedUseAppCheckTokens: Bool = false ) -> FirebaseAI {
38
57
let instance = createInstance (
39
58
app: app,
40
59
location: backend. location,
41
- apiConfig: backend. apiConfig
60
+ apiConfig: backend. apiConfig,
61
+ useLimitedUseAppCheckTokens: useLimitedUseAppCheckTokens
42
62
)
43
63
// Verify that the `FirebaseAI` instance is always configured with the production endpoint since
44
64
// this is the public API surface for creating an instance.
@@ -90,7 +110,8 @@ public final class FirebaseAI: Sendable {
90
110
tools: tools,
91
111
toolConfig: toolConfig,
92
112
systemInstruction: systemInstruction,
93
- requestOptions: requestOptions
113
+ requestOptions: requestOptions,
114
+ useLimitedUseAppCheckTokens: useLimitedUseAppCheckTokens
94
115
)
95
116
}
96
117
@@ -126,7 +147,8 @@ public final class FirebaseAI: Sendable {
126
147
apiConfig: apiConfig,
127
148
generationConfig: generationConfig,
128
149
safetySettings: safetySettings,
129
- requestOptions: requestOptions
150
+ requestOptions: requestOptions,
151
+ useLimitedUseAppCheckTokens: useLimitedUseAppCheckTokens
130
152
)
131
153
}
132
154
@@ -141,6 +163,8 @@ public final class FirebaseAI: Sendable {
141
163
142
164
let apiConfig : APIConfig
143
165
166
+ let useLimitedUseAppCheckTokens : Bool
167
+
144
168
/// A map of active `FirebaseAI` instances keyed by the `FirebaseApp` name and the `location`,
145
169
/// in the format `appName:location`.
146
170
private nonisolated ( unsafe) static var instances : [ InstanceKey : FirebaseAI ] = [ : ]
@@ -156,7 +180,8 @@ public final class FirebaseAI: Sendable {
156
180
)
157
181
158
182
static func createInstance( app: FirebaseApp ? , location: String ? ,
159
- apiConfig: APIConfig ) -> FirebaseAI {
183
+ apiConfig: APIConfig ,
184
+ useLimitedUseAppCheckTokens: Bool ) -> FirebaseAI {
160
185
guard let app = app ?? FirebaseApp . app ( ) else {
161
186
fatalError ( " No instance of the default Firebase app was found. " )
162
187
}
@@ -166,16 +191,27 @@ public final class FirebaseAI: Sendable {
166
191
// Unlock before the function returns.
167
192
defer { os_unfair_lock_unlock ( & instancesLock) }
168
193
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
+ )
170
200
if let instance = instances [ instanceKey] {
171
201
return instance
172
202
}
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
+ )
174
209
instances [ instanceKey] = newInstance
175
210
return newInstance
176
211
}
177
212
178
- init ( app: FirebaseApp , location: String ? , apiConfig: APIConfig ) {
213
+ init ( app: FirebaseApp , location: String ? , apiConfig: APIConfig ,
214
+ useLimitedUseAppCheckTokens: Bool ) {
179
215
guard let projectID = app. options. projectID else {
180
216
fatalError ( " The Firebase app named \" \( app. name) \" has no project ID in its configuration. " )
181
217
}
@@ -195,6 +231,7 @@ public final class FirebaseAI: Sendable {
195
231
)
196
232
self . apiConfig = apiConfig
197
233
self . location = location
234
+ self . useLimitedUseAppCheckTokens = useLimitedUseAppCheckTokens
198
235
}
199
236
200
237
func modelResourceName( modelName: String ) -> String {
@@ -249,5 +286,6 @@ public final class FirebaseAI: Sendable {
249
286
let appName : String
250
287
let location : String ?
251
288
let apiConfig : APIConfig
289
+ let useLimitedUseAppCheckTokens : Bool
252
290
}
253
291
}
0 commit comments