App Check

Protect your Firebase backend resources from abuse with reCAPTCHA v3 or reCAPTCHA Enterprise integration.

Overview

Firebase App Check helps protect your backend resources (Cloud Firestore, Realtime Database, Cloud Storage, Cloud Functions) from abuse by attesting that incoming traffic is coming from your app running on a genuine, untampered device.

FireBlazor provides seamless integration with App Check using reCAPTCHA v3 for web applications. For production environments, you can also use reCAPTCHA Enterprise for enhanced protection and additional features.

Important: Enable App Check First

You must enable App Check in the Firebase Console for your project before using it in your application. Navigate to App Check in the Firebase Console, register your app, and obtain your reCAPTCHA site key.

Key Features

  • reCAPTCHA v3 Integration - Invisible reCAPTCHA protection for web apps
  • reCAPTCHA Enterprise - Enhanced protection for production environments
  • Automatic Token Refresh - Tokens are automatically refreshed before expiration
  • Token Change Events - Subscribe to token updates for custom handling
  • Status Monitoring - Check activation status and current state

Configuration

Configure App Check in your Program.cs when setting up Firebase services. Use the UseAppCheck method with your reCAPTCHA site key.

Basic Setup with reCAPTCHA v3

// Program.cs
var builder = WebAssemblyHostBuilder.CreateDefault(args);

builder.Services.AddFirebase(options => options
    .WithProject("your-project-id")
    .WithApiKey("your-api-key")
    .WithAuthDomain("your-project.firebaseapp.com")
    .WithStorageBucket("your-project.firebasestorage.app")
    .WithDatabaseUrl("https://your-project.firebasedatabase.app")
    .UseAuth(auth => auth
        .EnableEmailPassword()
        .EnableGoogle("google-client-id"))
    .UseFirestore()
    .UseStorage()
    .UseRealtimeDatabase()
    .UseAppCheck(appCheck => appCheck
        .ReCaptchaV3("your-recaptcha-site-key")));

// Optional: Enable Blazor authorization
builder.Services.AddFirebaseAuthorization(options =>
{
    options.LoginPath = "/login";
    options.AccessDeniedPath = "/access-denied";
});
Getting Your reCAPTCHA Site Key

To obtain a reCAPTCHA site key, go to the reCAPTCHA Admin Console, create a new site with reCAPTCHA v3, and copy the site key. For reCAPTCHA Enterprise, use the Google Cloud Console.

Get Token

Use GetTokenAsync() to retrieve the current App Check token. This token can be sent to your backend services for verification.

@inject IFirebase Firebase

@code {
    private async Task GetAppCheckToken()
    {
        // Get App Check token
        var tokenResult = await Firebase.AppCheck.GetTokenAsync();

        if (tokenResult.IsSuccess)
        {
            var token = tokenResult.Value;
            Console.WriteLine($"Token: {token.Token}");
            Console.WriteLine($"Expires: {token.ExpirationTime}");

            // Use token for backend API calls
            await CallProtectedApiAsync(token.Token);
        }
        else
        {
            Console.WriteLine($"Error: {tokenResult.Error.Message}");
        }
    }

    private async Task CallProtectedApiAsync(string appCheckToken)
    {
        // Include the App Check token in your API requests
        httpClient.DefaultRequestHeaders.Add("X-Firebase-AppCheck", appCheckToken);
        var response = await httpClient.GetAsync("/api/protected");
    }
}

Token Properties

Property Type Description
Token string The App Check token string to send to your backend
ExpirationTime DateTime When the token expires (typically 1 hour from issuance)

Token Changes

Subscribe to the OnTokenChanged event to receive notifications when the App Check token is refreshed. This is useful for updating cached tokens or triggering re-authentication flows.

@inject IFirebase Firebase
@implements IDisposable

@code {
    protected override void OnInitialized()
    {
        // Subscribe to token changes
        Firebase.AppCheck.OnTokenChanged += HandleTokenChanged;
    }

    private void HandleTokenChanged(AppCheckToken? token)
    {
        if (token != null)
        {
            Console.WriteLine($"New token received");
            Console.WriteLine($"Expires at: {token.ExpirationTime}");

            // Calculate time until expiration
            var timeUntilExpiry = token.ExpirationTime - DateTime.UtcNow;
            Console.WriteLine($"Valid for: {timeUntilExpiry.TotalMinutes:F0} minutes");
        }
        else
        {
            Console.WriteLine("Token was invalidated");
        }

        InvokeAsync(StateHasChanged);
    }

    public void Dispose()
    {
        // Always unsubscribe to prevent memory leaks
        Firebase.AppCheck.OnTokenChanged -= HandleTokenChanged;
    }
}
Automatic Token Refresh

FireBlazor automatically refreshes App Check tokens before they expire. The OnTokenChanged event fires whenever a new token is obtained, allowing you to update any cached tokens in your application.

Check Status

Monitor the App Check activation status and current state using the IsActivated and Status properties.

@inject IFirebase Firebase

@code {
    private void CheckAppCheckStatus()
    {
        // Check if App Check is activated
        if (Firebase.AppCheck.IsActivated)
        {
            Console.WriteLine("App Check is active");
            Console.WriteLine($"Current status: {Firebase.AppCheck.Status}");
        }
        else
        {
            Console.WriteLine("App Check is not activated");
        }
    }
}

Status Properties

Property Type Description
IsActivated bool Returns true if App Check has been successfully initialized
Status AppCheckStatus Current status: NotInitialized, Initializing, Ready, or Error

Error Handling

FireBlazor uses a Result<T> pattern for error handling, providing a functional approach without exceptions. This pattern works consistently across all Firebase services, including App Check.

Pattern Matching

var result = await Firebase.AppCheck.GetTokenAsync();

// Pattern matching approach
var message = result.Match(
    onSuccess: token => $"Token valid until {token.ExpirationTime}",
    onFailure: error => $"Error: {error.Message}"
);

Console.WriteLine(message);

Imperative Style

var result = await Firebase.AppCheck.GetTokenAsync();

if (result.IsSuccess)
{
    var token = result.Value;
    Console.WriteLine($"Token: {token.Token}");
}
else
{
    var error = result.Error;
    Console.WriteLine($"[{error.Code}] {error.Message}");

    // Handle specific error codes
    switch (error.Code)
    {
        case "app-check/not-initialized":
            // App Check not configured properly
            break;
        case "app-check/recaptcha-error":
            // reCAPTCHA failed to load or verify
            break;
        default:
            // Other errors
            break;
    }
}

Exception Style

try
{
    // OrThrow() throws FirebaseException on failure
    var token = await Firebase.AppCheck.GetTokenAsync().OrThrow();
    Console.WriteLine($"Token obtained: {token.Token}");
}
catch (FirebaseException ex)
{
    Console.WriteLine($"Firebase error: {ex.Message}");
}

Common Error Codes

Error Code Description Resolution
app-check/not-initialized App Check was not properly configured Ensure UseAppCheck() is called during setup
app-check/recaptcha-error reCAPTCHA verification failed Check your site key and domain configuration
app-check/token-expired The App Check token has expired Call GetTokenAsync() to get a fresh token

Best Practices

Follow these recommendations to get the most out of App Check in your FireBlazor application.

1. Enable App Check in Firebase Console First

Before implementing App Check in your code, you must:

  • Navigate to the Firebase Console and select your project
  • Go to App Check in the left sidebar
  • Register your app with the appropriate attestation provider
  • Obtain your reCAPTCHA site key
  • Enable enforcement for the Firebase services you want to protect

2. Use reCAPTCHA Enterprise for Production

While reCAPTCHA v3 works well for development and testing, consider upgrading to reCAPTCHA Enterprise for production applications:

  • Enhanced bot detection algorithms
  • More granular risk scores
  • Better analytics and insights
  • Higher request quotas
  • SLA guarantees

3. Token Refresh is Automatic

FireBlazor handles token refresh automatically. You don't need to implement your own refresh logic. However, you should:

  • Subscribe to OnTokenChanged if you cache tokens locally
  • Always use fresh tokens for sensitive operations
  • Handle token retrieval errors gracefully

4. Implement Graceful Degradation

private async Task<bool> TryGetAppCheckToken()
{
    if (!Firebase.AppCheck.IsActivated)
    {
        // App Check not configured - decide how to handle
        return false;
    }

    var result = await Firebase.AppCheck.GetTokenAsync();

    return result.Match(
        onSuccess: token => {
            // Token obtained successfully
            _currentToken = token.Token;
            return true;
        },
        onFailure: error => {
            // Log error but don't block user
            _logger.LogWarning("App Check token failed: {Error}", error.Message);
            return false;
        }
    );
}

5. Test with Emulators

When using Firebase emulators, App Check is automatically bypassed. This allows you to develop and test your application without needing valid App Check tokens during local development.

Debug Token for Testing

For testing in non-production environments, you can register a debug token in the Firebase Console. This allows you to test App Check enforcement without needing reCAPTCHA verification.