google-apigoogle-cloud-consolegoogle-play-integrity-api

Decode integrity token using Google PlayIntegrity API


I am trying to implement PlayIntegrity API to my Android app, but I don't know how to decrypt and verify the token using Google's servers.

I followed the documentation up to this point:

Making request to the API

And now I am stuck on making the decode request to googleapis. I don't understand how does this instruction work.

I created a Service Account and I downloaded JSON credentials file and put it into my Laravel project, then I tried this piece of code:

$client = new Client();
$client->setAuthConfig(storage_path('app/integrity_check_account.json'));
$client->addScope(PlayIntegrity::class);
$httpClient = $client->authorize();

$result = $httpClient->request('POST', 'https://playintegrity.googleapis.com/v1/my.package.name', [
    'headers' => ['Content-Type' => 'application/json'],
    'body' => "{ 'integrity_token': 'token' }"
]);

dd($result);

So I having two issues with this code:

  1. Am I adding the scope correctly?
  2. Am I making the request correctly? Because it is not working as I am getting 404 error.

Solution

  • I finally found the solution to my problem while looking at the source of the PlayIntegrity API from the Google APIs Client Library for PHP.

    After importing required dependencies:

    composer require google/apiclient:^2.12.1
    

    This is my controller:

    <?php
    
    namespace App\Http\Controllers;
    
    use Google\Client;
    use Google\Service\PlayIntegrity;
    use Google\Service\PlayIntegrity\DecodeIntegrityTokenRequest;
    use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
    use Illuminate\Foundation\Bus\DispatchesJobs;
    use Illuminate\Foundation\Validation\ValidatesRequests;
    use Illuminate\Http\Request;
    use Illuminate\Routing\Controller as BaseController;
    
    class Controller extends BaseController {
        use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
    
        public function performCheck(Request $request) {
            $client = new Client();
            $client->setAuthConfig(path/to/your/credentials/json/file.json);
            $client->addScope(PlayIntegrity::PLAYINTEGRITY);
            $service = new PlayIntegrity($client);
            $tokenRequest = new DecodeIntegrityTokenRequest();
            $tokenRequest->setIntegrityToken("TOKEN_HERE");
            $result = $service->v1->decodeIntegrityToken('PACKGE_NAME_HERE', $tokenRequest);
            
            //Integrity check logic below
    
            //check with old nonce that you need to save somewhere
            if ($oldNonce !== $resultNonce) {
               echo "bad nonce";
               exit(1);
            }
    
            $deviceVerdict = $result->deviceIntegrity->deviceRecognitionVerdict;
            $appVerdict = $result->appIntegrity->appRecognitionVerdict;
            $accountVerdict = $result->accountDetails->appLicensingVerdict;
       
            //Possible values of $deviceVerdict[0] : MEETS_BASIC_INTEGRITY, MEETS_DEVICE_INTEGRITY, MEETS_STRONG_INTEGRITY
            if (!isset($deviceVerdict) || $deviceVerdict[0] !== 'MEETS_DEVICE_INTEGRITY') {
                  echo "device doesn't meet requirement";
                  exit(1);
            }
    
           //Possible values of $appVerdict: PLAY_RECOGNIZED, UNRECOGNIZED_VERSION, UNEVALUATED
            if ($appVerdict !== 'PLAY_RECOGNIZED') {
                echo "App not recognized";
                exit(1);
            }
    
           //Possible values of $accountVerdict: LICENSED, UNLICENSED, UNEVALUATED
           if ($accountVerdict !== 'LICENSED') {
               echo "User is not licensed to use app";
               exit(1);
           }
        }
    }
    
    

    Possible return verdicts are explained here.