Cannot Impersonate service account using PHP google/apiclient library

44 Views Asked by At

I'm trying to get a spreadsheet using service account and also impersonating the same account (works if I impersonate normal accounts with role Owner) but i got the error:

In REST.php line 134:
                                                             
  {                                                          
    "error": {                                               
      "code": 403,                                           
      "message": "The caller does not have permission",      
      "errors": [                                            
        {                                                    
          "message": "The caller does not have permission",  
          "domain": "global",                                
          "reason": "forbidden"                              
        }                                                    
      ],                                                     
      "status": "PERMISSION_DENIED"                          
    }                                                        
  }                                                          
   
  • I have been reading a lot and I know you have to setup some roles for that account to work as I did (i also added more testing):

enter image description here

$googleClient = new Google_Client();
$googleClient->setApplicationName('app name');
$googleClient->setScopes('https://www.googleapis.com/auth/spreadsheets');
$googleClient->setAccessType('offline');
$googleClient->setAuthConfig('config/credentials/service_account.json');
$googleClient->setSubject('[email protected]');      

$service = new Google_Service_Sheets($googleClient);
$response = $service->spreadsheets->get('myspreadhseetID');
  • My service_account.json is just a json downloadwed from key tab:
{
  "type": "service_account",
  "project_id": "myprojectname",
  "private_key_id": "myprivatekeyid",
  "private_key": "-----BEGIN PRIVATE KEY-----\n KEY HERE \n-----END PRIVATE KEY-----\n",
  "client_email": "[email protected]",
  "client_id": "myclientId",
  "auth_uri": "https://accounts.google.com/o/oauth2/auth",
  "token_uri": "https://oauth2.googleapis.com/token",
  "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
  "client_x509_cert_url":  "https://www.googleapis.com/robot/v1/metadata/x509/myserviceaccount%myserviceaccount.iam.gserviceaccount.com",
  "universe_domain": "googleapis.com"
}
1

There are 1 best solutions below

2
John Hanley On

You do not need to use impersonation. FYI: The service account you are using is trying to impersonate itself. That makes no sense. You are also calling functions intended for OAuth user authentication. Grant permission at Google Sheets for the service account email address (principal). In Google Sheets go to File -> Share -> Share with others. Enter the client_email of the service account.

Note: I did not check if you need additional scopes.

To do: Remove all of the IAM roles from the service account and most importantly Owner and all of the ones that include service account. Most of those allow the service account to use another service account which is dangerous. I don't think you need any IAM roles at all. Google Sheets is not part of Google Cloud and does not use Google Cloud IAM. Instead, Google Sheets uses OAuth access tokens with permissions granted by OAuth Scopes.

Use the following type of code:

$googleClient = new Google_Client();
$googleClient->setScopes('https://www.googleapis.com/auth/spreadsheets');
$googleClient->setAuthConfig('config/credentials/service_account.json');

$service = new Google_Service_Sheets($googleClient);
$response = $service->spreadsheets->get('myspreadhseetID');

You mentioned Domain Wide Delegation. I recommend that you do not use that reference. That grants too much power. The service account can impersonate super admins.

If you use DWD, you can use the service account to impersonate a user, but not another service account. The purpose of DWD is to impersonate a user in Google Workspace and not a service account in Google Cloud.