How to make SafetyNet/Firebase AppCheck work in Google Play Pre-Launch Reports

1.7k views Asked by At

I'm using Firebase AppCheck to authenticate that calls to my API are indeed coming from my app.

My issue is that ever since I enabled AppCheck, I can only get a token on legit devices or via debug tokens for the emulator. In a way this makes sense, but being unable to take advantage of Pre-Launch Reports is a pretty big caveat since they come in handy to ensure I don't ship a bugged version to my testers. Neither Pre-Launch Reports nor the Firebase Test Lab seem to have a way to pass SafetyNet.

Are all apps that use SafetyNet just unable to use Pre-Launch Reports or the Firebase Test Lab? That seems rather implausible to me, which is why I assume I'm missing something here.

Relevant code:

app/build.gradle:

dependencies {
    implementation platform('com.google.firebase:firebase-bom:29.3.1')
    implementation 'com.google.firebase:firebase-crashlytics-ktx'
    implementation 'com.google.firebase:firebase-analytics-ktx'
    implementation 'com.google.firebase:firebase-appcheck-safetynet:16.0.0-beta06'
    implementation 'com.google.firebase:firebase-appcheck-debug:16.0.0-beta06'

    // ...
}

In the onCreate() method of my Application class:

// ...

FirebaseApp.initializeApp(this)

val appCheck = FirebaseAppCheck.getInstance()

appCheck.installAppCheckProviderFactory(
    if (!BuildConfig.DEBUG) {
        SafetyNetAppCheckProviderFactory.getInstance()
    } else {
        Log.i(javaClass.name, "Using debug version of AppCheck.")
        DebugAppCheckProviderFactory.getInstance()
    }
)

// ...
2

There are 2 answers

0
Victor Fan On

Thank you for bringing this to our attention. The team is aware of the issue that apps with SafetyNet may not work correctly in Pre-launch Reports (PLR). However, Play Integrity API, which is also supported by App Check, should be supported by PLR soon--and since Play Integrity will soon replace SafetyNet, please consider migrating to Play Integrity regardless. In the meantime, as a workaround, you could tell your app to bypass SafetyNet Attestation and use debug tokens (similar to CI environments) if the app is running in Test Lab. To do this, see Modify instrumented test behavior for Test Lab.

1
Joao Gavazzi On

you might want to create a debug token on your project portal and try the following code:

object AppCheckFactoryProvider {

    fun get(context: Context): AppCheckProviderFactory {
        return when {
            isRunningOnTestDevice(context = context) -> CIDebugAppCheckProviderFactory()
            BuildConfig.DEBUG -> DebugAppCheckProviderFactory.getInstance()
            else -> PlayIntegrityAppCheckProviderFactory.getInstance()
        }
    }

    private fun isRunningOnTestDevice(context: Context): Boolean {
        return Settings.System.getString(
            context.contentResolver,
            FIREBASE_TEST_LAB_SETTINGS
        ) == "true"
    }

    private const val FIREBASE_TEST_LAB_SETTINGS = "firebase.test.lab"
}

class CIDebugAppCheckProviderFactory : AppCheckProviderFactory {

    override fun create(firebaseApp: FirebaseApp): AppCheckProvider {
        return DebugAppCheckProvider(firebaseApp, BuildConfig.APP_CHECK_DEBUG_TOKEN_FROM_CI)
    }
}

After that, you can inject the secret debug token into your build.

NOTE: Don't forget to rotate the token so often or ideally after each release, once the release cycle once it can be acquired if you decompile the APK.