0

There're three types of google api client_id:
1. Web Application
2. Service Account
3. Installed application

I have used 3. Installed application successfullly base on oauth2client, but failed on 2. Service Account. I wanna access my own gmail inbox with oauth2.0 Credentials.

import imaplib
import json
import urllib2
from oauth2client.client import SignedJwtAssertionCredentials
from httplib2 import Http
from apiclient.discovery import build
import os

reldir = os.path.dirname(os.path.relpath(__file__))
CLIENT_SECRET_FILE = os.path.join(reldir, 'gmail_service.json')
OAUTH_SCOPE = "https://mail.google.com"
GMAIL_ADDRESS = 'my_gmail_address@gmail.com'

def jwt_oauth2():
    '''
    https://developers.google.com/identity/protocols/OAuth2ServiceAccount
    '''
    with open(CLIENT_SECRET_FILE) as f:
        data = json.loads(f.read())
    private_key = data['private_key']
    client_email = data['client_email']
    credentials = SignedJwtAssertionCredentials(
        client_email,   private_key, scope=OAUTH_SCOPE)

    http_auth = credentials.authorize(Http())
    try:
        gmail_service = build('gmail', 'v1', http=http_auth)
        threads = gmail_service.users().messages().list(userId='me').execute()
    except Exception as e:
        return e

I got an exception same as the question. I encounter another exception while trying to add sub=GMAIL_ADDRESS into credentials:
AccessTokenRefreshError: unauthorized_client: Unauthorized client or scope in request.

I'm trying to figure out the problem, with credentials without sub:

>>> credentials = SignedJwtAssertionCredentials(
    client_email,   private_key, scope=OAUTH_SCOPE)
>>> http = credentials.authorize(Http())
>>> credentials.access_token
>>> credentials.refresh(http)
>>> credentials.access_token
u'ya29.pAGJjddCXjwsiHFN6hKU1yAkdWN7xMJbks5O76Pmrpe1hW1BbgwfZifjp81aDE55ALMVgjv-yBYiyQ'
>>> gmail_service = build('gmail', 'v1', http=http)
>>> request = gmail_service.users().messages().list(userId='me')
>>> response = request.execute()
{
 "error": {
  "errors": [
   {
    "domain": "global",
    "reason": "failedPrecondition",
    "message": "Bad Request"
   }
  ],
  "code": 400,
  "message": "Bad Request"
 }
}

Try to use credentials with sub:

>>> credentials = SignedJwtAssertionCredentials(
    client_email,   private_key, scope=OAUTH_SCOPE, sub=GMAIL_ADDRESS)
>>> http = credentials.authorize(Http())
>>> credentials.access_token
>>> credentials.refresh(http)
AccessTokenRefreshError: unauthorized_client: Unauthorized client or scope in request.

I found a similar question Google OAuth2 Service Account HTTP/REST Authentication, but I don't know much about node.js. Any help would be appreciated.

Community
  • 1
  • 1
LittleQ
  • 1,860
  • 1
  • 12
  • 14
  • Look at http://stackoverflow.com/questions/30947267/how-to-access-gmail-api/30955420#30955420 – ND003 Jul 02 '15 at 08:41
  • Service accounts cannot access @gmail.com mailboxes. You must use one of the other supported OAuth 2.0 authorization scenarios described at https://developers.google.com/identity/protocols/OAuth2. http://stackoverflow.com/a/39534420/3377170 has more details. – Brandon Jewett-Hall Sep 19 '16 at 15:49

1 Answers1

-1

You should use the sub field where you specify the account which you want to impersonate.

Say, using your service Account, you want to get details of a user user@domain.com, the sub field should be populated as:

sub: user@domain.com

You should also make sure that you have given the service Account access to users in the domain. Refer - https://developers.google.com/drive/web/delegation

ND003
  • 726
  • 1
  • 8
  • 22