Q: How can permission errors be resolved for Firebase App Check?
Background: I have enabled App Check per the documents:
DeviceCheck is enabled/configured per: https://firebase.google.com/docs/app-check/ios/devicecheck-provider
App Attest is enabled configured per: https://firebase.google.com/docs/app-check/ios/devicecheck-provider
SDK is added to the project, with code from: https://github.com/firebase/firebase-ios-sdk/blob/master/FirebaseAppCheck/Apps/FIRAppCheckTestApp/FIRAppCheckTestApp/AppDelegate.swift
Specifically, in appdelegate: Token setup:
FirebaseApp.configure()
requestDeviceCheckToken()
requestDebugToken()
if #available(iOS 14.0, *) {
requestAppAttestToken()
}
calling:
// MARK: App Check providers
func requestDeviceCheckToken() {
guard let firebaseApp = FirebaseApp.app() else {
return
}
DeviceCheckProvider(app: firebaseApp)?.getToken { token, error in
if let token = token {
print("DeviceCheck token: \(token.token), expiration date: \(token.expirationDate)")
}
if let error = error {
print("DeviceCheck error: \((error as NSError).userInfo)")
}
}
}
func requestDebugToken() {
guard let firebaseApp = FirebaseApp.app() else {
return
}
if let debugProvider = AppCheckDebugProvider(app: firebaseApp) {
print("Debug token: \(debugProvider.currentDebugToken())")
debugProvider.getToken { token, error in
if let token = token {
print("Debug FAC token: \(token.token), expiration date: \(token.expirationDate)")
}
if let error = error {
print("Debug error: \(error)")
}
}
}
}
@available(iOS 14.0, *)
func requestAppAttestToken() {
guard let firebaseApp = FirebaseApp.app() else {
return
}
guard let appAttestProvider = AppAttestProvider(app: firebaseApp) else {
print("Failed to instantiate AppAttestProvider")
return
}
appAttestProvider.getToken { token, error in
if let token = token {
print("App Attest FAC token: \(token.token), expiration date: \(token.expirationDate)")
}
if let error = error {
print("App Attest error: \(error)")
}
}
}
requestDeviceCheckToken()returns a permissions error:
DeviceCheck error: ["NSLocalizedFailureReason": The server responded with an error:
- URL: https://firebaseappcheck.googleapis.com/v1beta/projects/<GOOGLE_APP_ID>:exchangeDeviceCheckToken
- HTTP status code: 403
- Response body: {
"error": {
"code": 403,
"message": "Requests from this iOS client application \u003cempty\u003e are blocked.",
"status": "PERMISSION_DENIED",
"details": [
{
"@type": "type.googleapis.com/google.rpc.ErrorInfo",
"reason": "API_KEY_IOS_APP_BLOCKED",
"domain": "googleapis.com",
"metadata": {
"service": "firebaseappcheck.googleapis.com",
"consumer": "projects/<my project #>"
}
}
]
}
}
requestDebugToken() returns a permissions error:
Debug error: Error Domain=com.firebase.appCheck Code=0 "The server responded with an error:
- URL: https://firebaseappcheck.googleapis.com/v1beta/projects/<GOOGLE_APP_ID>:exchangeDebugToken
- HTTP status code: 403
- Response body: {
"error": {
"code": 403,
"message": "Requests from this iOS client application \u003cempty\u003e are blocked.",
"status": "PERMISSION_DENIED",
"details": [
{
"@type": "type.googleapis.com/google.rpc.ErrorInfo",
"reason": "API_KEY_IOS_APP_BLOCKED",
"domain": "googleapis.com",
"metadata": {
"consumer": "projects/<my project #>",
"service": "firebaseappcheck.googleapis.com"
}
}
]
}
}
" UserInfo={NSLocalizedFailureReason=The server responded with an error:
- URL: https://firebaseappcheck.googleapis.com/v1beta/projects/<GOOGLE_APP_ID>:exchangeDebugToken
- HTTP status code: 403
- Response body: {
"error": {
"code": 403,
"message": "Requests from this iOS client application \u003cempty\u003e are blocked.",
"status": "PERMISSION_DENIED",
"details": [
{
"@type": "type.googleapis.com/google.rpc.ErrorInfo",
"reason": "API_KEY_IOS_APP_BLOCKED",
"domain": "googleapis.com",
"metadata": {
"consumer": "projects/<my project #",
"service": "firebaseappcheck.googleapis.com"
}
}
]
}
}
}
requestAppAttestToken() returns an error:
App Attest error: Error Domain=com.firebase.appCheck Code=0 "(null)"
GCP Console does show all calls to the following w/ 100% errors:
google.firebase.appcheck.v1beta.TokenExchangeService.ExchangeDebugToken
google.firebase.appcheck.v1beta.TokenExchangeService.ExchangeDeviceCheckToken
google.firebase.appcheck.v1beta.TokenExchangeService.GenerateAppAttestChallenge
All of which seem to point to a permissions error? Specifically, GOOGLE_APP_ID is in the request URL, but App Check is configured in Firebase via the console...
I'm not seeing anything in the docs or anything obvious in IAM that I missed? :(
Ty in advance for help!
Update After further testing w/ Postman:
The issue seems to be that the SDK isn't passing the X-Ios-Bundle-Identifier
correctly when calling AppCheck API(s).
Steps to get to this conclusion:
- From POSTMAN: API call w/ original API_KEY -> yields initial (above) error response/403
- From POSTMAN: API call as above, + X-Ios-Bundle-Identifier + valid debug_token -> yields success payload.
So:
- any ideas to help ID why the
X-Ios-Bundle-Identifier
isn't being passed by the SDK? The app is using other Firebase API's w/out issue, so seems limited to the AppCheck SDK... - and/or - can the
X-Ios-Bundle-Identifier
be programmatically added (in Swift) to the AppCheck calls (it is properly notated in the .plist)
Resolved!
App Check SDK does not currently support the Android / iOS Application Restriction for API keys. With that, you must remove the App Restriction for your API keys to resolve this issue.
Hopefully, the Application Restriction(s) will be supported at some point...
Update!
v8.8.0-beta now supports the bundle ID! :)