Search code examples
google-api-dotnet-client

Google Play Integrity API Scope


I need to use Google Play Integrity API

I am trying to use the scope provided in the documentation here - https://googleapis.dev/dotnet/Google.Apis.PlayIntegrity.v1/latest/api/Google.Apis.PlayIntegrity.v1.PlayIntegrityService.Scope.html

But I receive this error - The service playintegrity has thrown an exception. HttpStatusCode is Forbidden. Request had insufficient authentication scopes.

When I try to open the link itself I get this message: *You are receiving this error either because your input OAuth2 scope name is invalid or it refers to a newer scope that is outside the domain of this legacy API.

This API was built at a time when the scope name format was not yet standardized. This is no longer the case and all valid scope names (both old and new) are catalogued at https://developers.google.com/identity/protocols/oauth2/scopes. Use that webpage to lookup (manually) the scope name associated with the API you are trying to call and use it to craft your OAuth2 request.*

When I try to search for it in https://developers.google.com/identity/protocols/oauth2/scopes. I cannot find it, I would think it might have been discontinued but there seems to be recent development on this API according to GitHub. https://github.com/googleapis/google-api-dotnet-client.

The API is enabled in google cloud on the project. I've also tried adding it to the Google OAuth Screen Scopes but it also doesn't show up as a possible option. OAuth Consent screen

The code used when trying to access this API:

UserCredential credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
            new ClientSecrets
            {
                ClientId = "x",
                ClientSecret = "y"
            },
            new [] { "https://www.googleapis.com/auth/playintegrity"},
            "user",
            CancellationToken.None
        );
         

        var service = new PlayIntegrityService(new BaseClientService.Initializer
        {
            ApplicationName = "Test",
            HttpClientInitializer = credential
        });

        // Create the DecodeIntegrityTokenRequest body with your nonce as the IntegrityToken.
        DecodeIntegrityTokenRequest requestBody = new DecodeIntegrityTokenRequest()
        {
            IntegrityToken = nonce.ToString()
        };

        // The package name of the app.
        string packageName = "Test";

        // Create the DecodeIntegrityTokenRequest.
        V1Resource.DecodeIntegrityTokenRequest request = new V1Resource.DecodeIntegrityTokenRequest(service, requestBody, packageName);

        // Execute the request and get the response.
        DecodeIntegrityTokenResponse response = await request.ExecuteAsync();

        // Now, response.TokenPayloadExternal contains the decoded integrity payload.
        TokenPayloadExternal payload = response.TokenPayloadExternal;

Solution

  • I'll explain my PlayIntegrity implementation further:

    Important: In my case I work with 2 projects in Google Console Cloud, development and production.

    Step 1: Google Console Cloud (Non-production)

    1. Sign in to Google Console Cloud.
    2. Go to APIs and Services and search for “Google Play Integrity API”.
    3. Enable the service.
    4. Press the “Google Cloud” logo to go home and then enter IAM and administration.
    5. In Service Accounts, create a new one, assign a name, and select roles:
    • Service account user.
    • Service Usage Consumer.
    1. After creating it, a key with type json must be created
    2. Save the json because it is what is used to invoke the services.

    Step 2: Google Play Console (Production)

    1. Enter the Google Play Console, in “App Integrity”, press “Link Cloud Project”
    2. Select the project and finish the form.
    3. Verify that the response is the recommended one (encrypted)
    4. Enter Google Cloud and perform the same steps to activate PlayIntegrity and the other steps to download the json.

    Step 3: Create nonce on server

    Create a unique text and save it in a table, record if it has already been used to avoid response replicas. TableNonce(Id,IdDevice,Nonce,DateUsed)

    Step 4: Client (Xamarin)

    In the client you must add the Nuget: Xamarin.Google.Android.Play.Integrity And it is invoked as follows:

    public async Task<string> InvokeApi(string elNonce, bool isProduction)
    {
        //you can make a loop for try if fails
        var context = Application.Context;
        var elIntegrityManagerFactory = IntegrityManagerFactory.Create(context);
        var elBuilder = IntegrityTokenRequest.InvokeBuilder().SetNonce(elNonce);
    
        if (!isProduction)
        {
            elBuilder.SetCloudProjectNumber(4231000); // ID GoogleCloudProject
        }
    
        var elIntegrityTokenResponseObject = await elIntegrityManagerFactory.RequestIntegrityToken(elBuilder.Build());
        var elIntegrityTokenResponse = (IntegrityTokenResponse)elIntegrityTokenResponseObject;
        return elIntegrityTokenResponse.Token();
    }
    

    Step 5: Server

    A method is added for the Google Token to be decrypted:

    public TokenPayloadExternal Decrypt()
    {
        var elGoogleCredential = GoogleCredential.FromJson(JsonCredentials);
        var elInitializer = new BaseClientService.Initializer()
        {
            HttpClientInitializer = elGoogleCredential,
            ApplicationName = ApplicationName
        };
        var elRequest = new DecodeIntegrityTokenRequest()
        {
            IntegrityToken = Attestation
        };
        var elServicio = new PlayIntegrityService(elInitializer);
        var elResultado = elServicio.V1.DecodeIntegrityToken(elRequest, ApkPackageName);
        return elResultado.Execute().TokenPayloadExternal;
    }
    
    • JsonCredentials: The full text of the downloaded JSON. Implement logic to use production or development json.
    • ApplicationName: Name of the application *It is not known what it is used for but it does not affect the name that is sent.
    • ApkPackageName: Name of the package.
    • Attestation: It is the client's encrypted Token.

    Once the response is decrypted, perform validations: Verdicts

    Used Google Translator