35

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.

Jay Fowler
  • 65
  • 6
user1333358
  • 359
  • 1
  • 3
  • 3
  • 1
    This Error has started occurring for us as well. Have had no issues to date. If we use IMAP everything is fine - looks like there is some issue with Gmail API. Google Help?? – PNC Oct 01 '14 at 07:30
  • Has this worked before or did it just break? If it just broke can you give the time at which it broke? If it has never worked, can you confirm it's a service account, whitelisted in Cpanel and provide more details on the domain-wide setup? You're using something like: https://developers.google.com/accounts/docs/OAuth2ServiceAccount#formingclaimset I imagine? – Eric D Oct 01 '14 at 16:06
  • 1
    Can you also post what the value is you're using for the "userId" field in your requests? Is it "me", the user's email address that should match the auth token or something else? – Eric D Oct 01 '14 at 16:31
  • 3
    That error should only occur if you're using a userId param that differs from the authorized user. That style of delegation isn't supported. Correct way is to impersonate the user when fetching the access token and stick to using 'me' as userId. – Steve Bazyl Oct 01 '14 at 21:59
  • Hi Eric, Steve - the issue for us occurred yesterday morning for the first time. We have not had a problem prior to this. We are using the userId of the delegated user. The only thing I can think of is that it is a group mailbox? Error message is Google.Apis.Requests.RequestError Delegation denied for support.rd@xnns.com [403] Errors [ Message[Delegation denied for support.rd@xnns.com] Location[ - ] Reason[forbidden] Domain[global] ] – PNC Oct 01 '14 at 22:46
  • The other strange thing is that for the same user we can happily use IMAP - which is what we are currently doing to get around this issue. – PNC Oct 01 '14 at 22:50
  • 2
    Just use: userId="me" when making your call to the Gmail API. For service account with domain-wide delegation the only time you specify the email address is for the 'sub' parameter when you're requesting the access token. – Eric D Oct 01 '14 at 23:34
  • I'm having a hard time finding any requests for "support.rd@xnns.com". Can you provide the first 8 digits of the Developer Client ID you're using? – Eric D Oct 01 '14 at 23:42
  • Hi Eric - domain is mxns.com – PNC Oct 02 '14 at 00:09
  • Can you check using userId="me" for the requests? – Eric D Oct 02 '14 at 00:13
  • OK will do - just ran request now and generated the error. Client ID digits are 48629482 – PNC Oct 02 '14 at 00:15
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/62301/discussion-between-pnc-and-eric-defriez). – PNC Oct 02 '14 at 00:36
  • Hi guys, not sure if I should open a new question, but I'm having something similar happen to me, and changing to userId=me works but in an entirely unexpected way. I'm using v2.0.0-RC4 of google/google-api-php-client to send an email, and occasionally, it tries to delegate to a user that isn't the person who the access token or user id belongs to and who isn't the session user. It is however another user who is logged into my app, which is only open to people within my GApps domain. I've logged the access token and user id, I have no idea where it's getting the other ID from. – AJ Cerqueti Feb 05 '16 at 12:06
  • For me, this is probably related to https://github.com/google/google-api-php-client/issues/821 so not related to this issue, apologies. – AJ Cerqueti Feb 05 '16 at 13:03

5 Answers5

78

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.

Eric D
  • 6,901
  • 1
  • 15
  • 26
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'])
Guo Huang
  • 923
  • 8
  • 8
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 = 'someuser@my.domain';

// 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);


?>
Jay Fowler
  • 65
  • 6
0

I wanted to access the emails of fresh email id/account but what happened was, the recently created folder with '.credentials' containing a JSON was associated with the previous email id/account which I tried earlier. The access token and other parameters present in JSON are not associated with new email id/account. So, in order make it run you just have to delete the '.credentails' folder and run the program again. Now, the program opens the browser and asks you to give permissions.

To delete the folder containing files in python

import shutil
shutil.rmtree("path of the folder to be deleted")

you may add this at the end of the program

grooveplex
  • 2,492
  • 4
  • 28
  • 30
Sai Kiran
  • 74
  • 5
0

Recently I started exploring Gmail API and I am following the same approach as Guo mentioned. However, it is going to take of time and too many calls when we the number of users or more. After domain wide delegation my expectation was admin id will be able to access the delegated inboxes, but seems like we need to create service for each user.

Afiz
  • 11
  • 2
    Is this meant to be an answer? Or commentary? Please only post answers in the answer section. – ChrisGPT was on strike Jul 16 '20 at 18:16
  • You definitely do not require a service per user. Domain wide delegation should work, in combination with the primaryEmail of the user instead of 'me' – Air2 Apr 04 '23 at 09:05