configureFirebaseAnonymousAuth function

Future<Map<String, dynamic>> configureFirebaseAnonymousAuth({
  1. required String project,
  2. required bool initialize,
  3. required bool enableAnonymous,
  4. required AuthConfigRequest request,
})

Inspects configuration and applies only explicitly authorized missing state.

Only CONFIGURATION_NOT_FOUND allows initialization. No other provider is included in the update mask, and a fresh GET must verify the resulting state.

Implementation

Future<Map<String, dynamic>> configureFirebaseAnonymousAuth({
  required String project,
  required bool initialize,
  required bool enableAnonymous,
  required AuthConfigRequest request,
}) async {
  final path = "/admin/v2/projects/$project/config";
  var response = await request("GET", path, null);
  var initialized = false;
  var updated = false;
  if (response.status == 404 &&
      (response.body["error"] as Map?)?["message"] ==
          "CONFIGURATION_NOT_FOUND" &&
      initialize) {
    final created = await request(
        "POST", "/v2/projects/$project/identityPlatform:initializeAuth", null);
    _requireSuccess(created, "initialize");
    initialized = true;
    response = await request("GET", path, null);
  }
  _requireSuccess(response, "get");
  final before = response.body;
  if (_anonymousEnabled(before) != true && enableAnonymous) {
    final changed = await request("PATCH", path, {
      "name": "projects/$project/config",
      "signIn": {
        "anonymous": {"enabled": true}
      },
    });
    _requireSuccess(changed, "update");
    updated = true;
    response = await request("GET", path, null);
    _requireSuccess(response, "verify");
    if (_anonymousEnabled(response.body) != true) {
      throw StateError("Fresh Auth config does not confirm anonymous enabled.");
    }
    // Compare every other sign-in field, ignoring only the approved field.
    final oldSignIn = Map<String, dynamic>.from(before["signIn"] as Map? ?? {});
    final newSignIn =
        Map<String, dynamic>.from(response.body["signIn"] as Map? ?? {});
    for (final map in [oldSignIn, newSignIn]) {
      final anonymous =
          Map<String, dynamic>.from(map["anonymous"] as Map? ?? {});
      anonymous.remove("enabled");
      map.remove("anonymous");
      if (anonymous.isNotEmpty) {
        map["anonymous"] = anonymous;
      }
    }
    if (_canonical(oldSignIn) != _canonical(newSignIn)) {
      throw StateError(
          "Unrelated sign-in configuration changed during verification.");
    }
  }
  return {
    "project_id": project,
    "config_present": true,
    "anonymous_enabled": _anonymousEnabled(response.body),
    "initialized": initialized,
    "anonymous_updated": updated,
    "other_signin_fields_preserved": true,
    "verified_at": DateTime.now().toUtc().toIso8601String(),
  };
}