javaauthenticationgoogle-analytics-apiruntimeexception

Google Analytics 4 API - service account has full admin privileges - still PERMISSION DENIED to all API calls


I have the following Java code to try and get a single metric from GA4 using the GA4 Java bindings / classes:

String propertyId = "123123123";

GoogleCredentials gc = ServiceAccountCredentials.fromStream(this.getClass().getResourceAsStream("/client_secrets.json"))
                    .createScoped(Collections.singletonList(StorageScopes.DEVSTORAGE_FULL_CONTROL));

            BetaAnalyticsDataSettings betaAnalyticsDataSettings = BetaAnalyticsDataSettings.newBuilder().setCredentialsProvider(FixedCredentialsProvider.create(gc)).build();

            BetaAnalyticsDataClient betaAnalyticsDataClient = BetaAnalyticsDataClient.create(betaAnalyticsDataSettings);

RunReportRequest request = RunReportRequest.newBuilder().setProperty("properties/" + propertyId).
                    addMetrics(Metric.newBuilder().setName("active7DayUsers")).
                    addDateRanges(DateRange.newBuilder().
                            setStartDate("2023-07-31").setEndDate("today")).build();

            RunReportResponse response = betaAnalyticsDataClient.runReport(request);

This results in an exception in the RunReportResponse generation, e. g.

com.google.api.gax.rpc.PermissionDeniedException: io.grpc.StatusRuntimeException: PERMISSION_DENIED: Request had insufficient authentication scopes

How can I get sufficient authentication scope?

I have so far

Any ideas or pointers?

I've worked through every GUI option I can find, I have full admin permissions set for the GA4 Account and Property, and using the GA4 GUI I can SEE the properties are there, data is accumulating, etc. - everything is working EXCEPT the API.

The issue is incredibly common and I've worked through several posts about this, but there is simply no resolution.

I've also tried downgrading each permission for both the Account and Property, and upgrading them in all possible combinations, keep getting

com.google.api.gax.rpc.PermissionDeniedException: io.grpc.StatusRuntimeException: PERMISSION_DENIED: Request had insufficient authentication scope

What am I doing wrong? Is there something wrong with the code above?

Thanks


Solution

  • Please check another option as well: Go to your analytics.google account and click on Management of access to the property or Property Access Management (Sorry my page is in Italian language and I am using Translate to English option of my browser to be comprehensible) enter image description here

    then you should see the email available in client_secrets.json file here having the Administrator role.

    enter image description here

    Java Part:

    Supposing credentialsJsonPath variable is a String and the path to your secret json file, and propertyId is the variable containing your client propertyId.
    ... Files.createDirectories(Paths.get(credentialsJsonPath).getParent());

                    GoogleCredentials credentials =
                            GoogleCredentials.fromStream(new FileInputStream(credentialsJsonPath));
        
                    BetaAnalyticsDataSettings betaAnalyticsDataSettings =
                            BetaAnalyticsDataSettings.newBuilder()
                            .setCredentialsProvider(FixedCredentialsProvider.create(credentials))
                            .build();    
        
                    try (BetaAnalyticsDataClient analyticsData =
                            BetaAnalyticsDataClient.create(betaAnalyticsDataSettings)) {
                         
                        int offset=0;
                        int limit=100000;
    RunReportRequest request =
                    RunReportRequest.newBuilder()
                    .setProperty("properties/" + propertyId)
    .addDateRanges(DateRange.newBuilder().setStartDate("your start date").setEndDate("your end date"))
    
    
                    .addDimensions(Dimension.newBuilder().setName("date")) 
                    .addDimensions(Dimension.newBuilder().setName("eventName"))
    
                    .addMetrics(Metric.newBuilder().setName("eventCount"))
                    .addMetrics(Metric.newBuilder().setName("eventsPerSession"))
                    .addMetrics(Metric.newBuilder().setName("eventValue"))
    .setOffset(offset)
                    .setLimit(limit)
                    .build();
    
        RunReportResponse response = analyticsData.runReport(request);
                    System.out.println(response);
     }catch(Exception e){
    e.printStackTrace();
    }
    

    ofcourse, you can read any other compatible dimensions/metrics, I just used some examples.