Search code examples
flutterfirebasegoogle-geminifirebase-vertex-ai

"The caller does not have permission " in Vertex AI for Firebase SDK


I am developing a Flutter application that uses the Vertex AI for Firebase SDK. When I use only a text prompt without any Firebase Storage URL, everything works fine. However, when including a Firebase Storage URL, I receive the following error message: The caller does not have permission.

I found that changing the Firebase Storage security rules to the following solves the problem, but these rules are not secure:

rules_version = '2';
service firebase.storage {
  match /b/{bucket}/o {
    match /{allPaths=**} {
      allow read, write: if true;
    }
  }
}
Stream<String?> generateTextFromMediaStream(String promptText, List<String>? mediaPaths) async* {
    
      final prompt = TextPart(promptText);
      List mediaPartsFuture = [];
      if (mediaPaths != null) {
        mediaPartsFuture = mediaPaths.map((path)  {
          final mimeType = getMimeType(path);
          return FileData(mimeType, path);

        }).toList();
      
      }

      final response = _model.generateContentStream([
        Content.multi([prompt, ...mediaPartsFuture])
      ]);

      await for (final chunk in response) {
        yield chunk.text;
      }
  }

Error Messages:

I/flutter (12483): The caller does not have permission
I/flutter (12483): #0      parseGenerateContentResponse (package:google_generative_ai/src/api.dart:558:54)
I/flutter (12483): #1      _MapStream._handleData (dart:async/stream_pipe.dart:213:31)
I/flutter (12483): #2      _ForwardingStreamSubscription._handleData (dart:async/stream_pipe.dart:153:13)
I/flutter (12483): #3      _RootZone.runUnaryGuarded (dart:async/zone.dart:1594:10)
I/flutter (12483): #4      _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:365:11)
I/flutter (12483): #5      _BufferingStreamSubscription._add (dart:async/stream_impl.dart:297:7)
I/flutter (12483): #6      _SyncStreamControllerDispatch._sendData (dart:async/stream_controller.dart:784:19)
I/flutter (12483): #7      _StreamController._add (dart:async/stream_controller.dart:658:7)
I/flutter (12483): #8      _StreamController.add (dart:async/stream_controller.dart:606:5)
I/flutter (12483): #9      _AsyncStarStreamController.add (dart:async-patch/async_patch.dart:76:16)
I/flutter (12483): #10     HttpApiClient.streamRequest (package:google_generative_ai/src/client.dart)
I/flutter (12483): <asynchronous suspension>
I/flutter (12483): #11     _ForwardingStreamSubscription._handleData (dart:async/stream_pipe.dart:152:3)
I/flutter (12483): <asynchronous suspension>

I see in Google Cloud APIS the following errors:

Firebase ML API:

  • Methods: google.firebase.machinelearning.v2beta.PredictionService.StreamGenerateContent (100% Error)

Additional Context:

Flutter 3.22.0 firebase_vertexai 0.1.0+1

Could someone guide me on what might be causing this permission error and how to resolve it without compromising the security of Firebase Storage rules?

What I've Tried:

  1. I attempted to use the following more restrictive security rules, but they did not work:
rules_version = '2';
service firebase.storage {
  match /b/{bucket}/o {
    match /{allPaths=**} {
      allow read, write: if request.auth != null ||                         request.auth.token.email.matches('.*gserviceaccount.*') ||
                          request.auth.token.email == '[email protected]'||
                          request.auth.token.email == 'service-PROJECT_NUMBER@gcp-sa-aiplatform-cc.iam.gserviceaccount.com'||
                          request.auth.token.email == '[email protected]'||
                          request.auth.token.email == '[email protected]'||
                          request.auth.token.email == '[email protected]' ||
                          request.auth.token.email == '[email protected]' ||
                          request.auth.token.email == 'service-PROJECT_NUMBER@gcp-sa-firebasestorage.iam.gserviceaccount.com';
    }
  }
}

I replaced PROJECT_NUMBER with my project number

  1. I give roles to following rol (Cloud Storage for Firebase Admin ) to service accounts:

Solution

  • Probably the Firebase VertexAI SDK uses a service account to access the storage bucket (or not using authentication at all).

    Edit: The main solution would be to authenticate the VertexAI service or SDK using the current FirebaseAuth instance to be able to make authenticated requests to the Firebase Cloud Storage.
    To authenticate the VertexAI SDK, pass the current FirebaseAuth instance to it when initiating a new VertexAI instance as following:

    final vertexAI = FirebaseVertexAI.instanceFor(
      auth: FirebaseAuth.instance, // The existing FirebaseAuth instance if the user is authenticated.
      location: 'location');
    
    print(vertexAI.auth?.currentUser?.email); // Check if authentication was successful.
    

    However, here's a quick and dirty solution that might be relevant to you if the user isn't authenticated or the resources were uploaded recently for example:

    rules_version = '2';
    
    // Grants a user access to a node matching their user ID
    service firebase.storage {
      match /b/{bucket}/o {
        // Files look like: "user/<UID>/path/to/file.txt"
        match /user/{userId}/{allPaths=**} {
          // Allow read if the file was created less than 10 minutes ago
          allow read: if request.time < resource.timeCreated + duration.value(10, 'm');
          // Allow write if authenticated and UID matches or if the user has admin privileges
          allow write: if request.auth != null && (request.auth.uid == userId || request.auth.token.admin == true);
        }
      }
    }
    
    

    Otherwise, you can handle resource download yourself, then pass it to the service as raw bytes.