Share
Embed
Protect your backends with Firebase App Check
A powerful layer of security for your backend infrastructure that helps protect access to your services by attesting that incoming traffic is coming from your app, and blocking traffic that doesn't have valid credentials. It helps protect your backend from abuse, such as billing fraud, phishing, app impersonation, and data poisoning.
Firebase Thailand
October 01, 2022
Transcript
54 slides
-
Bangkok Protect your backends with Firebase App Check Jirawat Karanwittayakarn
Google Developer Expert in Firebase -
Release and Monitor Crashlytics Performance Monitoring Test Lab Engage In-App
Messaging Predictions Cloud Messaging Remote Config A/B Testing Dynamic Links Build Auth Cloud Functions Cloud Firestore Cloud Storage Hosting Realtime Database -
Firebase Resources Cloud Firestore Cloud Storage for Firebase Realtime Database
Cloud Functions for Firebase -
Attestation Providers SafetyNet Device Check reCAPTCHA V3 Custom Attestation New
App Attest reCAPTCHA Enterprise New Play Integrity New reCAPTCHA V3 SafetyNet Device Check -
To support prior versions to iOS 11, use custom attestation.
Device Check Supported on iOS 11+ Only supported on iOS 14+ App Attest And -
App Check Backend Issues App Check token with TTL in
Attestation flow App Check token grants access to Firestore while TTL is valid -
App Check Backend App Check token exceeds TTL Re-perform Attestation
flow to keep valid App Check token Issues App Check token with TTL in Attestation flow -
App Check Backend Refreshed App Check token with valid TTL
Re-perform Attestation flow to keep valid App Check token Issues App Check token with TTL in Attestation flow -
30 Min 7 Days Short TTL Long TTL Recommend 1
hr for most apps Custom TTL -
App Check Service Access User Data + Security Rules Firebase
Auth Better together Firebase Security -
const express = require('express'); const app = express(); const firebaseAdmin
= require('firebase-admin'); const firebaseApp = firebaseAdmin.initializeApp(); const appCheckVerification = async (req, res, next) => { // implementation details next slide. } app.get('/yourApiEndpoint', [appCheckVerification], (req, res) => { // Handle request. }); App Check in the Backend Service -
const appCheckVerification = async (req, res, next) => { const
appCheckToken = req.header('X-Firebase-AppCheck'); if (!appCheckToken) { res.status(401); return next('Unauthorized'); } try { const appCheckClaims = await firebaseAdmin.appCheck().verifyToken(appCheckToken); // If verifyToken() succeeds, continue with the next middleware function return next(); } catch (err) { res.status(401); return next('Unauthorized'); } } App Check in the Backend Service -
const appCheckVerification = async (req, res, next) => { const
appCheckToken = req.header('X-Firebase-AppCheck'); if (!appCheckToken) { res.status(401); return next('Unauthorized'); } try { const appCheckClaims = await firebaseAdmin.appCheck().verifyToken(appCheckToken); // If verifyToken() succeeds, continue with the next middleware function return next(); } catch (err) { res.status(401); return next('Unauthorized'); } } App Check in the Backend Service -
const appCheckVerification = async (req, res, next) => { const
appCheckToken = req.header('X-Firebase-AppCheck'); if (!appCheckToken) { res.status(401); return next('Unauthorized'); } try { const appCheckClaims = await firebaseAdmin.appCheck().verifyToken(appCheckToken); // If verifyToken() succeeds, continue with the next middleware function return next(); } catch (err) { res.status(401); return next('Unauthorized'); } } App Check in the Backend Service -
const appCheckVerification = async (req, res, next) => { const
appCheckToken = req.header('X-Firebase-AppCheck'); if (!appCheckToken) { res.status(401); return next('Unauthorized'); } try { const appCheckClaims = await firebaseAdmin.appCheck().verifyToken(appCheckToken); // If verifyToken() succeeds, continue with the next middleware function return next(); } catch (err) { res.status(401); return next('Unauthorized'); } } App Check in the Backend Service -
class ApiWithAppCheckExample { interface YourExampleBackendService { @GET("yourExampleEndpoint") fun exampleData( @Header("X-Firebase-AppCheck")
appCheckToken: String ): Call<List<String>> } var yourExampleBackendService: YourExampleBackendService = Retrofit.Builder() .baseUrl("https://yourbackend.example.com/") .build() .create(YourExampleBackendService::class.java) fun callApiExample() { FirebaseAppCheck.getInstance().getAppCheckToken(false) .addOnSuccessListener { tokenResponse -> val appCheckToken = tokenResponse.token val apiCall = yourExampleBackendService.exampleData(appCheckToken) // ... } } } Custom Backend for Android -
class ApiWithAppCheckExample { interface YourExampleBackendService { @GET("yourExampleEndpoint") fun exampleData( @Header("X-Firebase-AppCheck")
appCheckToken: String ): Call<List<String>> } var yourExampleBackendService: YourExampleBackendService = Retrofit.Builder() .baseUrl("https://yourbackend.example.com/") .build() .create(YourExampleBackendService::class.java) fun callApiExample() { FirebaseAppCheck.getInstance().getAppCheckToken(false) .addOnSuccessListener { tokenResponse -> val appCheckToken = tokenResponse.token val apiCall = yourExampleBackendService.exampleData(appCheckToken) // ... } } } Custom Backend for Android -
class ApiWithAppCheckExample { interface YourExampleBackendService { @GET("yourExampleEndpoint") fun exampleData( @Header("X-Firebase-AppCheck")
appCheckToken: String ): Call<List<String>> } var yourExampleBackendService: YourExampleBackendService = Retrofit.Builder() .baseUrl("https://yourbackend.example.com/") .build() .create(YourExampleBackendService::class.java) fun callApiExample() { FirebaseAppCheck.getInstance().getAppCheckToken(false) .addOnSuccessListener { tokenResponse -> val appCheckToken = tokenResponse.token val apiCall = yourExampleBackendService.exampleData(appCheckToken) // ... } } } Custom Backend for Android -
class ApiWithAppCheckExample { interface YourExampleBackendService { @GET("yourExampleEndpoint") fun exampleData( @Header("X-Firebase-AppCheck")
appCheckToken: String ): Call<List<String>> } var yourExampleBackendService: YourExampleBackendService = Retrofit.Builder() .baseUrl("https://yourbackend.example.com/") .build() .create(YourExampleBackendService::class.java) fun callApiExample() { FirebaseAppCheck.getInstance().getAppCheckToken(false) .addOnSuccessListener { tokenResponse -> val appCheckToken = tokenResponse.token val apiCall = yourExampleBackendService.exampleData(appCheckToken) // ... } } } Custom Backend for Android -
AppCheck.appCheck().token(forcingRefresh: false) { token, error in guard error == nil
else { return } guard let token = token else { return } let tokenString = token.token let url = URL(string: "https://yourbackend.example.com/yourApiEndpoint")! var request = URLRequest(url: url) request.httpMethod = "GET" request.setValue(tokenString, forHTTPHeaderField: "X-Firebase-AppCheck") let task = URLSession.shared.dataTask(with: request) { data, response, error in // Handle response from your backend. } task.resume() } Custom Backend for iOS -
AppCheck.appCheck().token(forcingRefresh: false) { token, error in guard error == nil
else { return } guard let token = token else { return } let tokenString = token.token let url = URL(string: "https://yourbackend.example.com/yourApiEndpoint")! var request = URLRequest(url: url) request.httpMethod = "GET" request.setValue(tokenString, forHTTPHeaderField: "X-Firebase-AppCheck") let task = URLSession.shared.dataTask(with: request) { data, response, error in // Handle response from your backend. } task.resume() } Custom Backend for iOS -
AppCheck.appCheck().token(forcingRefresh: false) { token, error in guard error == nil
else { return } guard let token = token else { return } let tokenString = token.token let url = URL(string: "https://yourbackend.example.com/yourApiEndpoint")! var request = URLRequest(url: url) request.httpMethod = "GET" request.setValue(tokenString, forHTTPHeaderField: "X-Firebase-AppCheck") let task = URLSession.shared.dataTask(with: request) { data, response, error in // Handle response from your backend. } task.resume() } Custom Backend for iOS -
const callApiWithAppCheckExample = async () => { let appCheckTokenResponse; try
{ appCheckTokenResponse = await firebase.appCheck().getToken(false); } catch (err) { return; } const apiResponse = await fetch('https://yourbackend.example.com/yourApiEndpoint', { headers: { 'X-Firebase-AppCheck': appCheckTokenResponse.token, } }); // Handle response from your backend. }; Custom Backend for Web -
const callApiWithAppCheckExample = async () => { let appCheckTokenResponse; try
{ appCheckTokenResponse = await firebase.appCheck().getToken(false); } catch (err) { return; } const apiResponse = await fetch('https://yourbackend.example.com/yourApiEndpoint', { headers: { 'X-Firebase-AppCheck': appCheckTokenResponse.token, } }); // Handle response from your backend. }; Custom Backend for Web -
void callApiExample() async { final appCheckToken = await FirebaseAppCheck.instance.getToken(); if
(appCheckToken != null) { final response = await http.get( Uri.parse("https://yourbackend.example.com/yourExampleEndpoint"), headers: {"X-Firebase-AppCheck": appCheckToken}, ); } else { // Error: couldn't get an App Check token. } } Custom Backend for Flutter -
void callApiExample() async { final appCheckToken = await FirebaseAppCheck.instance.getToken(); if
(appCheckToken != null) { final response = await http.get( Uri.parse("https://yourbackend.example.com/yourExampleEndpoint"), headers: {"X-Firebase-AppCheck": appCheckToken}, ); } else { // Error: couldn't get an App Check token. } } Custom Backend for Flutter -
void callApiExample() async { final appCheckToken = await FirebaseAppCheck.instance.getToken(); if
(appCheckToken != null) { final response = await http.get( Uri.parse("https://yourbackend.example.com/yourExampleEndpoint"), headers: {"X-Firebase-AppCheck": appCheckToken}, ); } else { // Error: couldn't get an App Check token. } } Custom Backend for Flutter