Firebase-interviewvragen 2026: Flutter Auth, Firestore en Security Rules

Firebase-interviewvragen voor Flutter-developers, met antwoorden in Dart: auth state streams, Google Sign-In v7, Firestore CRUD en datamodellering, security rules, custom claims, transacties en de wijzigingen in FlutterFire 5.

Flutter Firebase Authentication Firestore 2026

Firebase-interviewvragen voor Flutter-functies draaien om vijf onderwerpen: de drie auth state streams, datamodellering in Firestore, security rules, offline writes en het kostenmodel achter elke read. Firebase blijft in 2026 de standaardbackend voor Flutter-apps, en sinds oktober 2026 verschijnen de FlutterFire-plugins als BoM 5.x (firebase_core 5.1.0, firebase_auth 7.0.1, cloud_firestore 7.1.0), met een Android-minSdk die naar 24 is verhoogd en de Firebase Apple SDK 13 eronder.

FlutterFire BoM 5.1.0 (oktober 2026)

De huidige FlutterFire-release is BoM 5.1.0: firebase_auth 7.0.1, cloud_firestore 7.1.0, firebase_core 5.1.0. De major 5.0.0 vereist Android-minSdk 24, bouwt op de Firebase Apple SDK 13.0.0 en hernoemt de activate-parameters van App Check. Firestore Pipelines, toegevoegd in cloud_firestore 6.3.0, krijgen bij elke release nieuwe expressies.

Firebase-interviewvragen: wat er in 2026 gevraagd wordt

Interviewers vragen zelden naar API-weetjes. Ze toetsen of een kandidaat begrijpt waar Firebase regels afdwingt, wat elke operatie kost en wat er gebeurt als het netwerk wegvalt. De tabel koppelt de terugkerende onderwerpen aan wat een sterk antwoord moet bevatten. Elk onderwerp wordt verderop uitgebreid beantwoord in de sectie Firebase-interviewvragen voor Flutter-developers.

OnderwerpTypische vraagWat een sterk antwoord bevat
Auth streamsauthStateChanges() vs idTokenChanges() vs userChanges()Welke events elke stream uitzendt, en welke de navigatie bewaakt
BeveiligingWaar wordt toegangscontrole afgedwongen?Security rules op de server, nooit checks in de client; App Check is een andere laag
RollenHoe implementeer je een adminrol?Custom claims gezet via de Admin SDK, gelezen via request.auth.token
DatamodelleringModelleer een chat-appSubcollections, gedenormaliseerd laatste bericht, één document per bericht
ConsistentieTransactie of batched write?Transacties lezen, schrijven daarna en worden opnieuw geprobeerd; batches schrijven alleen, atomair
OfflineWat gebeurt er met een write zonder netwerk?Lokale cache, hasPendingWrites, synchronisatie bij herverbinding
KostenWaarom is dit scherm duur?Facturering per gelezen document, listeners, paginering met cursors
VergelijkingFirestore vs Realtime DatabaseQuerymodel, schaalbaarheid, factureringseenheid

Firebase Project Setup en Initialisatie

De eerste stap bij elke Firebase-integratie is het configureren van het Firebase project en het initialiseren van de SDK in de Flutter app. Sinds FlutterFire CLI v0.3 is dit proces aanzienlijk vereenvoudigd.

Developers gebruiken flutterfire configure om automatisch platform-specifieke configuratiebestanden te genereren. Dit commando maakt een firebase_options.dart bestand aan met alle benodigde API keys en project identifiers voor iOS, Android en Web.

main.dartdart
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'firebase_options.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  // Initialize Firebase with platform-specific config
  await Firebase.initializeApp(
    options: DefaultFirebaseOptions.currentPlatform,
  );
  runApp(const MyApp());
}

De ensureInitialized() methode garandeert dat de Flutter engine volledig is opgestart voordat asynchrone Firebase-initialisatie plaatsvindt. De currentPlatform getter selecteert automatisch de juiste configuratie op basis van het draaiende platform.

Multi-tenancy ondersteuning

Flutter apps kunnen meerdere Firebase projects gebruiken via Firebase.initializeApp(name: 'secondary', options: ...). Dit is nuttig voor apps die verschillende environments (development, staging, production) ondersteunen binnen dezelfde build.

Email/Password Authenticatie met FirebaseAuth

De firebase_auth package biedt een declaratieve API voor gebruikersbeheer, met email/password, OAuth-providers (Google, Apple, GitHub), sms-verificatie en multi-factor authenticatie, sinds firebase_auth 6.1.0 ook TOTP op macOS. De AuthService class kapselt alle authenticatielogica in en biedt foutafhandeling voor veelvoorkomende scenario's.

auth_service.dartdart
import 'package:firebase_auth/firebase_auth.dart';

class AuthService {
  final FirebaseAuth _auth = FirebaseAuth.instance;

  // Register with email and password
  Future<User?> register(String email, String password) async {
    try {
      final credential = await _auth.createUserWithEmailAndPassword(
        email: email,
        password: password,
      );
      return credential.user;
    } on FirebaseAuthException catch (e) {
      // Handle specific error codes
      switch (e.code) {
        case 'email-already-in-use':
          throw Exception('This email is already registered');
        case 'weak-password':
          throw Exception('Password must be at least 6 characters');
        default:
          throw Exception('Registration failed: ${e.message}');
      }
    }
  }

  // Sign in with existing credentials
  Future<User?> signIn(String email, String password) async {
    final credential = await _auth.signInWithEmailAndPassword(
      email: email,
      password: password,
    );
    return credential.user;
  }

  // Reactive auth state stream
  Stream<User?> get authStateChanges => _auth.authStateChanges();
}

De authStateChanges() stream is de hoeksteen van reactieve authenticatie in Flutter. Widgets kunnen deze stream gebruiken met StreamBuilder om automatisch te reageren op login/logout events zonder handmatige state management.

Wachtwoordregels hoeven niet langer alleen in de client te staan: de validatePassword-API (beschikbaar sinds firebase_auth 6.0.0) toetst een wachtwoord aan het beleid dat in de Firebase Console is ingesteld, dat een minimale lengte, hoofdletters, kleine letters, cijfers en speciale tekens kan vereisen.

Google Sign-In Integratie

OAuth providers zoals Google vereisen een extra package. Sinds google_sign_in 7.0 is de plugin een singleton die via GoogleSignIn.instance wordt opgehaald, precies één keer moet worden geïnitialiseerd, en authenticatie staat los van autorisatie. De aanroep GoogleSignIn().signIn() uit oudere tutorials compileert niet meer.

google_auth.dartdart
import 'package:firebase_auth/firebase_auth.dart';
import 'package:google_sign_in/google_sign_in.dart';

// Call once at startup, before any other GoogleSignIn method
Future<void> initGoogleSignIn() => GoogleSignIn.instance.initialize();

Future<UserCredential> signInWithGoogle() async {
  try {
    // Shows the native account picker; throws if the user cancels
    final googleUser = await GoogleSignIn.instance.authenticate();

    // Synchronous getter since v7: only the ID token is exposed here
    final googleAuth = googleUser.authentication;

    // Firebase only needs the ID token to create the credential
    final credential = GoogleAuthProvider.credential(
      idToken: googleAuth.idToken,
    );
    return FirebaseAuth.instance.signInWithCredential(credential);
  } on GoogleSignInException catch (e) {
    if (e.code == GoogleSignInExceptionCode.canceled) {
      throw Exception('Sign-in cancelled');
    }
    rethrow;
  }
}

Deze methode demonstreert de credential exchange flow: Google tokens worden omgezet naar een Firebase credential die vervolgens wordt gebruikt voor authenticatie. Dit patroon is identiek voor andere OAuth providers zoals Apple, Facebook en Microsoft. Moet de app ook een Google-API aanroepen (Drive, Calendar), dan komt het access token nu uit een aparte stap, authorizationClient.authorizeScopes, zoals beschreven in de migratiegids van google_sign_in.

Interviewvalkuil: Google Sign-In v7

Een kandidaat die GoogleSignIn().signIn() schrijft en accessToken uit authentication leest, citeert de API van vóór 7.0. In v7 geeft authenticate() het account terug, bevat authentication alleen nog het idToken, en vereisen access tokens voor extra scopes een expliciete autorisatie-aanroep.

iOS configuratie vereist

Google Sign-In op iOS vereist een geconfigureerde URL scheme in Info.plist. De FlutterFire documentatie bevat platform-specifieke setup guides die deze stappen in detail uitleggen.

Firestore CRUD Operaties met Cloud Firestore

Cloud Firestore is een NoSQL document database die realtime synchronisatie en offline persistence ondersteunt. De cloud_firestore package biedt een type-safe API voor alle database operaties.

firestore_service.dartdart
import 'package:cloud_firestore/cloud_firestore.dart';

class TaskService {
  final _db = FirebaseFirestore.instance;
  final String _collection = 'tasks';

  // Create a new document with auto-generated ID
  Future<String> createTask(String userId, String title) async {
    final doc = await _db.collection(_collection).add({
      'userId': userId,
      'title': title,
      'completed': false,
      'createdAt': FieldValue.serverTimestamp(),
    });
    return doc.id;
  }

  // Read a single document by ID
  Future<Map<String, dynamic>?> getTask(String taskId) async {
    final snapshot = await _db.collection(_collection).doc(taskId).get();
    return snapshot.data();
  }

  // Update specific fields without overwriting the entire document
  Future<void> toggleComplete(String taskId, bool completed) async {
    await _db.collection(_collection).doc(taskId).update({
      'completed': completed,
      'updatedAt': FieldValue.serverTimestamp(),
    });
  }

  // Delete a document
  Future<void> deleteTask(String taskId) async {
    await _db.collection(_collection).doc(taskId).delete();
  }
}

De FieldValue.serverTimestamp() methode garandeert consistente timestamps tussen clients met verschillende tijdzones. Firestore gebruikt deze server-side timestamps voor accurate ordering en synchronisatie. Sinds cloud_firestore 7.1.0 komen FieldValue.minimum en FieldValue.maximum bij de server-side transforms: ze bewaren de laagste of hoogste waarde van opgeslagen en inkomende waarde zonder voorafgaande read, wat past bij tellers zoals een topscore.

Realtime Synchronisatie met Snapshots

De kracht van Firestore ligt in realtime streams. De snapshots() methode retourneert een Stream die automatisch updates pushed wanneer data wijzigt.

real_time_tasks.dartdart
import 'package:cloud_firestore/cloud_firestore.dart';

class TaskStream {
  final _db = FirebaseFirestore.instance;

  // Stream all tasks for a specific user, ordered by creation date
  Stream<List<Map<String, dynamic>>> userTasks(String userId) {
    return _db
        .collection('tasks')
        .where('userId', isEqualTo: userId)
        .orderBy('createdAt', descending: true)
        .snapshots()
        .map((snapshot) => snapshot.docs.map((doc) {
              final data = doc.data();
              data['id'] = doc.id; // Include document ID
              return data;
            }).toList());
  }
}

Deze stream kan direct worden gebruikt in een StreamBuilder widget. Elke keer dat een task wordt toegevoegd, gewijzigd of verwijderd, ontvangt de UI automatisch een update zonder polling of manual refresh.

Klaar om je Flutter gesprekken te halen?

Oefen met onze interactieve simulatoren, flashcards en technische tests.

Firestore Security Rules voor Productie

Firestore security rules vormen de eerste verdedigingslinie tegen ongeautoriseerde toegang. Deze declaratieve regels worden server-side afgedwongen en kunnen niet worden omzeild door gemanipuleerde client code.

firestore.rulesjavascript
rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    // Users can only access their own profile
    match /users/{userId} {
      allow read, update: if request.auth != null
                          && request.auth.uid == userId;
      allow create: if request.auth != null;
      allow delete: if false; // Prevent self-deletion
    }

    // Tasks belong to the user who created them
    match /tasks/{taskId} {
      allow read, write: if request.auth != null
                         && resource.data.userId == request.auth.uid;
      allow create: if request.auth != null
                    && request.resource.data.userId == request.auth.uid;
    }
  }
}

De request.auth variabele bevat de huidige gebruiker. De resource.data verwijst naar bestaande documenten, terwijl request.resource.data de inkomende data representeert bij create/update operaties.

Test rules grondig

De Firebase Console bevat een Rules Playground waar developers security rules kunnen testen met gesimuleerde requests. Dit is essentieel voor het voorkomen van data leaks in productie.

Offline Persistentie en Synchronisatie

Firestore ondersteunt automatische offline persistence. Writes worden lokaal in een cache opgeslagen en gesynchroniseerd zodra de netwerk connectie hersteld is.

offline_aware_widget.dartdart
StreamBuilder<DocumentSnapshot>(
  stream: FirebaseFirestore.instance
      .collection('tasks')
      .doc(taskId)
      .snapshots(),
  builder: (context, snapshot) {
    if (!snapshot.hasData) return const CircularProgressIndicator();

    final data = snapshot.data!;
    final isPending = data.metadata.hasPendingWrites;

    return Row(
      children: [
        Text(data['title']),
        if (isPending) const Icon(Icons.cloud_upload, size: 16),
      ],
    );
  },
)

De hasPendingWrites property geeft aan of een document lokale wijzigingen heeft die nog niet naar de server zijn gesynchroniseerd. Dit is cruciaal voor het tonen van accurate loading states in de UI.

Cache Configuratie

Developers kunnen de cache size en persistentie gedrag configureren:

dart
FirebaseFirestore.instance.settings = Settings(
  persistenceEnabled: true,
  cacheSizeBytes: Settings.CACHE_SIZE_UNLIMITED,
);

De default cache size is 40MB. Voor apps met veel data is CACHE_SIZE_UNLIMITED aan te raden, maar dit kan storage problemen veroorzaken op devices met weinig ruimte.

Repository Pattern voor Testbare Code

Direct gebruik van Firestore in UI code maakt unit testing complex. Het Repository pattern scheidt data access logica van business logic.

task_repository.dartdart
abstract class TaskRepository {
  Future<String> create(String userId, String title);
  Stream<List<Task>> watchAll(String userId);
  Future<void> update(String id, Map<String, dynamic> fields);
  Future<void> delete(String id);
}

// firebase_task_repository.dart
class FirebaseTaskRepository implements TaskRepository {
  final _db = FirebaseFirestore.instance;

  
  Future<String> create(String userId, String title) async {
    final doc = await _db.collection('tasks').add({
      'userId': userId,
      'title': title,
      'completed': false,
      'createdAt': FieldValue.serverTimestamp(),
    });
    return doc.id;
  }

  
  Stream<List<Task>> watchAll(String userId) {
    return _db
        .collection('tasks')
        .where('userId', isEqualTo: userId)
        .orderBy('createdAt', descending: true)
        .snapshots()
        .map((s) => s.docs.map(Task.fromFirestore).toList());
  }

  // ... update and delete implementations
}

Dit patroon maakt het mogelijk om een MockTaskRepository te creëren voor unit tests. De business logic blijft ongewijzigd, alleen de repository implementatie wordt vervangen. State management-oplossingen zoals Riverpod of BLoC gebruiken de repository-interface zonder iets van Firestore te weten.

Dependency Injection

Packages zoals get_it of riverpod maken het eenvoudig om repository instances te injecteren. Dit verbetert testability en maakt het wisselen tussen implementaties (bijv. Firebase vs local database) triviaal.

Upgraden naar FlutterFire 5: wat er breekt

De major release van oktober 2026 (BoM 5.0.0, firebase_auth 7.0.0, cloud_firestore 7.0.0, firebase_core 5.0.0) verandert vooral de buildvereisten, minder de Dart-API's. Op deze punten faalt een build of een review:

  • Android-minSdk 24: de plugins bouwen op de Firebase Android BoM 35. Een project dat nog op minSdk 21 of 23 staat, compileert niet meer.
  • Apple SDK 13: de Firebase Apple SDK gaat naar 13.0.0 met Swift Package Manager (12.19.0 met CocoaPods), en Swift packages vereisen macOS 11.
  • App Check: de activate-parameters heten nu providerWeb, providerAndroid en providerApple.
  • Deprecations: setIndexConfigurationFromJSON is deprecated in cloud_firestore 7.0.0, en firebase_ml_model_downloader wordt niet meer gepubliceerd.
  • Al verwijderd in de 6.x-reeks: fetchSignInMethodsForEmail() en User.updateEmail(). Code die vóór het inloggen controleert welke provider een e-mailadres gebruikt, moet opnieuw worden ontworpen, omdat de bescherming tegen e-mailenumeratie die informatie verbergt.

De volledige lijst per package staat in de FlutterFire release notes en de changelog van cloud_firestore.

Firebase-interviewvragen voor Flutter-developers

Interviews toetsen zowel conceptueel begrip als de praktische implementatie van Firebase-diensten. De volgende vragen komen in 2026 regelmatig terug in interviews voor Flutter-developers. De bredere gids met Flutter-interviewvragen behandelt de frameworkkant.

Wat is het verschil tussen authStateChanges(), idTokenChanges() en userChanges()?

authStateChanges() vuurt alleen bij in- en uitloggen. idTokenChanges() vuurt daarnaast wanneer het ID-token wordt vernieuwd (ongeveer elk uur). userChanges() vangt dat allemaal op, plus profielwijzigingen zoals updateDisplayName(). Voor de meeste navigation guards volstaat authStateChanges().

Wat is het verschil tussen set() en update() in Firestore?

De set() methode overschrijft het volledige document. Als het document niet bestaat, wordt het aangemaakt. De update() methode wijzigt alleen opgegeven velden en faalt als het document niet bestaat. Voor partiële updates is update() de juiste keuze.

Hoe werkt de offline synchronisatie van Firestore?

Firestore gebruikt een lokale SQLite database om alle gelezen documenten te cachen. Writes worden opgeslagen in een write-ahead log en automatisch gesynchroniseerd bij netwerkverbinding. De snapshots() stream emits eerst cached data, gevolgd door server updates.

Waarom is FieldValue.serverTimestamp() beter dan DateTime.now()?

Client timestamps zijn onbetrouwbaar door tijdzone verschillen en gemanipuleerde device clocks. Server timestamps garanderen consistente ordering en worden pas ingevuld na de write commit.

Hoe voorkom je N+1 queries bij nested collections?

Firestore ondersteunt geen joins. Voor relational data gebruiken developers denormalization (data dupliceren) of batched reads met whereIn() queries. Collection Group Queries kunnen queries uitvoeren over alle subcollections met dezelfde naam.

Hoe modelleer je Firestore-data voor een chatapplicatie?

Een collection chats waarin elk document de metadata bevat (deelnemers, timestamp van het laatste bericht), met onder elk chatdocument een subcollection messages. Met deze structuur haal je de chatlijst van een gebruiker efficiënt op en pagineer je de berichten binnen elk gesprek. Het laatste bericht wordt gedenormaliseerd in het bovenliggende document, zodat de lijstweergave de subcollection niet hoeft te lezen.

Wat zijn de limieten van Firestore composite indexes?

Elke query die meerdere where() clauses combineert met orderBy() vereist een composite index. Firebase genereert automatisch single-field indexes, maar composite indexes moeten handmatig worden aangemaakt via de Console of firestore.indexes.json.

Wanneer gebruik je een transactie in plaats van een batched write?

Een transactie is nodig wanneer de write afhangt van data die in dezelfde operatie wordt gelezen, bijvoorbeeld de voorraad alleen verlagen als die boven nul ligt. De SDK voert de callback opnieuw uit als een gelezen document vóór de commit verandert, dus de callback mag geen side effects hebben. Een batched write voert meerdere writes atomair uit zonder enige read, bijvoorbeeld een document aanmaken en elders een teller ophogen. Offline gedragen ze zich verschillend: een batch komt in de wachtrij, een transactie faalt zonder verbinding.

dart
final db = FirebaseFirestore.instance;

// Transaction: read then write, retried on contention
await db.runTransaction((tx) async {
  final ref = db.collection('products').doc(id);
  final snap = await tx.get(ref);
  final stock = snap.get('stock') as int;
  if (stock <= 0) throw Exception('Out of stock');
  tx.update(ref, {'stock': stock - 1});
});

// Batched write: atomic writes, no reads
final batch = db.batch();
batch.set(db.collection('orders').doc(), {'productId': id});
batch.update(db.collection('stats').doc('orders'), {
  'count': FieldValue.increment(1),
});
await batch.commit();

Hoe implementeer je een adminrol met Firebase?

Met custom claims die vanuit een vertrouwde omgeving via de Admin SDK worden gezet, nooit vanuit de Flutter-client. De claim reist mee in het ID-token, dus rules lezen hem als request.auth.token.admin == true zonder extra document-lookup. De documentatie over custom claims beperkt de payload tot 1000 bytes, en de client ziet een nieuwe claim pas na een tokenvernieuwing, die currentUser.getIdToken(true) afdwingt.

Wat is het verschil tussen security rules en App Check?

Security rules bepalen of een bepaalde gebruiker een bepaald document mag lezen of schrijven. App Check bevestigt dat het verzoek van de echte app op een echt toestel komt, wat scripts blokkeert die de publieke API-key hergebruiken. Ze beantwoorden verschillende vragen, dus een productie-app heeft ze allebei nodig. Sinds FlutterFire 5 wordt App Check geactiveerd met providerAndroid, providerApple en providerWeb.

Waarom kan een Firestore-scherm duur worden, en hoe werkt paginering?

Firestore factureert per gelezen, geschreven en verwijderd document. Een listener op een onbegrensde collection leest bij de eerste load elk overeenkomend document, daarna één read per gewijzigd document. Paginering gebruikt query cursors in plaats van offsets: limit(20) voor de eerste pagina, daarna startAfterDocument(lastDoc) voor de volgende, zodat elke pagina alleen de documenten kost die ze teruggeeft.

Firestore of Realtime Database: welke en waarom?

Firestore slaat documenten op in collections, ondersteunt samengestelde queries met indexes en factureert per operatie. De Realtime Database slaat één JSON-boom op, biedt ondiepe queries op één child key en factureert vooral op bandbreedte en opslag, wat past bij kleine, zeer frequente updates zoals presence-indicatoren. De meeste nieuwe Flutter-apps starten op Firestore en voegen de Realtime Database alleen toe voor presence.

Voor verdere voorbereiding op Flutter-interviews behandelen speciale oefenmodules deze onderwerpen met interactieve quizzen en challenges op tijd.

Begin met oefenen!

Test je kennis met onze gespreksimulatoren en technische tests.

Bronnen

Flutter en Firebase in het interview: de kernpunten

  • FlutterFire BoM 5.1.0 levert firebase_auth 7.0.1 en cloud_firestore 7.1.0 en vereist Android-minSdk 24
  • google_sign_in 7 vervangt GoogleSignIn().signIn() door GoogleSignIn.instance.initialize() gevolgd door authenticate(), en Firebase heeft alleen het idToken nodig
  • authStateChanges() levert een reactieve stream die de loginstatus in de hele app beheert zonder handmatige checks
  • Realtime synchronisatie via snapshots() maakt polling overbodig en sluit direct aan op StreamBuilder voor automatische UI-updates
  • Security rules zijn verplicht in productie: controleer request.auth.uid altijd tegen de eigenaarsvelden van het document en gebruik custom claims voor rollen
  • Transacties lezen en schrijven daarna met retries, batched writes schrijven alleen; paginering gebruikt cursors omdat elk gelezen document gefactureerd wordt
  • Offline persistence werkt op mobiel zonder extra code; hasPendingWrites toont gebruikers de synchronisatiestatus
  • Het Repository pattern ontkoppelt Firebase van de business logic, wat testen en latere migraties eenvoudiger maakt
Dagelijkse challenge

Zie jij de bug in Flutter?

Een echt codefragment, een verborgen bug, één poging per dag. Zonder account uit te proberen.

Anthony Fillion-Maillet

Geschreven door

Anthony Fillion-Maillet

Oprichter van SharpSkill

Al meer dan 10 jaar fullstack-ontwikkelaar. Hij leidt SharpSkill en staat in voor alles wat hier verschijnt.

Bijgewerkt op 9 november 2026

Tags

#flutter
#firebase
#authentication
#firestore
#dart

Delen

Gerelateerde artikelen