Gmail API returns 403 error code and "Delegation denied for <user email>"

29,727

Solution 1

Seems like best thing to do is to just always have userId="me" in your requests. That tells the API to just use the authenticated user's mailbox--no need to rely on email addresses.

Solution 2

Our users had migrated into a domain and their account had aliases attached to it. We needed to default the SendAs address to one of the imported aliases and want a way to automate it. The Gmail API looked like the solution, but our privileged user with roles to make changes to the accounts was not working - we kept seeing the "Delegation denied for " 403 error.

Here is a PHP example of how we were able to list their SendAs settings.

<?PHP

//
// Description:
//   List the user's SendAs addresses.
//
// Documentation:
//   https://developers.google.com/gmail/api/v1/reference/users/settings/sendAs
//   https://developers.google.com/gmail/api/v1/reference/users/settings/sendAs/list
//
// Local Path:
//   /path/to/api/vendor/google/apiclient-services/src/Google/Service/Gmail.php
//   /path/to/api/vendor/google/apiclient-services/src/Google/Service/Gmail/Resource/UsersSettingsSendAs.php
//
// Version:
//    Google_Client::LIBVER  == 2.1.1
//

require_once $API_PATH . '/path/to/google-api-php-client/vendor/autoload.php';

date_default_timezone_set('America/Los_Angeles');

// this is the service account json file used to make api calls within our domain
$serviceAccount = '/path/to/service-account-with-domain-wide-delagation.json';
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $serviceAccount );

$userKey = '[email protected]';

// In the Admin Directory API, we may do things like create accounts with 
// an account having roles to make changes. With the Gmail API, we cannot 
// use those accounts to make changes. Instead, we impersonate
// the user to manage their account.

$impersonateUser = $userKey;

// these are the scope(s) used.
define('SCOPES', implode(' ', array( Google_Service_Gmail::GMAIL_SETTINGS_BASIC ) ) );

$client = new Google_Client();
$client->useApplicationDefaultCredentials();  // loads whats in that json service account file.
$client->setScopes(SCOPES); // adds the scopes
$client->setSubject($impersonateUser);  // account authorized to perform operation

$gmailObj  = new Google_Service_Gmail($client);

$res       = $gmailObj->users_settings_sendAs->listUsersSettingsSendAs($userKey);

print_r($res);


?>

Solution 3

I had the same issue before, the solution is super tricky, you need to impersonate the person you need to access gmail content first, then use userId='me' to run the query. It works for me.

here is some sample code:

   users = # coming from directory service
   for user in users:
     credentials = service_account.Credentials.from_service_account_file(
        SERVICE_ACCOUNT_FILE, scopes=SCOPES)
     ####IMPORTANT######
     credentials_delegated = credentials.with_subject(user['primaryEmail'])

     gmail_service = build('gmail', 'v1', credentials=credentials_delegated)

     results = gmail_service.users().labels().list(userId='me').execute()
     labels = results.get('labels', [])
       for label in labels:
          print(label['name'])
Share:
29,727
Admin
Author by

Admin

Updated on July 17, 2020

Comments

  • Admin
    Admin almost 4 years

    Gmail API fails for one domain when retrieving messages with this error:

    com.google.api.client.googleapis.json.GoogleJsonResponseException: 403 OK
    {
      "code" : 403,
      "errors" : [ {
        "domain" : "global",
        "message" : "Delegation denied for <user email>",
        "reason" : "forbidden"
      } ],
      "message" : "Delegation denied for <user email>"
    }
    

    I am using OAuth 2.0 and Google Apps Domain-Wide delegation of authority to access the user data. The domain has granted data access rights to the application.