Search code examples
pythongoogle-apigmail

Google service account authentication Python: 401 Request had invalid authentication credentials


I am writing a script that needs to connect to the Google API and download some emails. This script will run in a server, so I need to make sure that it does not require user interaction when authenticating.

The documentation suggest to use a service account for server-to-server applications. I followed the tutorial in the docs, but it comes back with 401.

from google.oauth2.service_account import Credentials
from googleapiclient.discovery import build
from typing import List, Dict
import logging


logging.basicConfig(format='%(asctime)s - %(message)s', level=logging.INFO)


SCOPES = ['https://www.googleapis.com/auth/gmail.readonly']
KEYWORD = "LinkedIn"


def login() -> Credentials:
    try:
        credentials = Credentials.from_service_account_file('credentials.json', scopes=SCOPES)
        return credentials

    except Exception as ex:
        logging.error(f"-----ERROR-----login: {ex}")
        



def get_unread_messages(credentials) -> List[Dict]:
    try:

        service = build('gmail', 'v1', credentials=credentials)

        result = service.users().messages().list(userId='me', labelIds=["INBOX", "UNREAD"]).execute()

        message_ids = result.get('messages')
        unread_messages = [service.users().messages().get(userId='me', id=msg['id']).execute() for msg in message_ids]

        return unread_messages

    except Exception as ex:
        logging.error(f"-----ERROR-----get_unread_messages:{ex}")

credentials = login()
get_unread_messages(credentials )

** Error message**

------ERROR-----get_unread_messages:<HttpError 401 when requesting https://gmail.googleapis.com/gmail/v1/users/me/messages?labelIds=INBOX&labelIds=UNREAD&alt=json returned "Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.". Details: "[{'message': 'Invalid Credentials', 'domain': 'global', 'reason': 'authError', 'location': 'Authorization', 'locationType': 'header'}]">


Solution

  • service account authorization only works with google workspace domain accounts after you have configured domain wide deligation and added a user impersonation to you code.

    for standard Gmail accounts you need to use Oauth2 and authorize the user once and store the refresh token