2
votes

We are experiencing problems with Authentication of Service Accounts for domain-wide delegation. The main problem is it's hard to investigate and debug the auth configuration so we would like to ask for some tips how to debug the configuration. Or maybe we are missing some configuration options and you can point us to them.

Our process is:

  1. Create SA(=Service Account) with enabled domain-wide delegation.
  2. Authenticate SA in GSuite admin console(https://support.google.com/a/answer/162106?hl=en).
    • use client_id from the credentials file. (now email)
    • scopes are comma-separated without spaces between.
  3. Ensure the "Security > API Reference > API Reference -> 'Enable API Access'" is checked.

For some GSuite domains this is working configuration, but we got some domains where this configuration results in:

google.auth.exceptions.RefreshError: ('unauthorized_client: Client is unauthorized to retrieve access tokens using this method.', '{\n "error": "unauthorized_client",\n "error_description": "Client is unauthorized to retrieve access tokens using this method."\n}')

In our understanding, this is the error saying the client_id and scopes were not added to the "Manage API client access" page. (=List of authenticated clients)

We really ensured that the GSuite domain we are requesting has the proper client_id and scopes added in the list of authenticated clients + has the 'Enabled API Access'. We even created Shared Desktop with them and did it by ourselves to be fully sure of it. But the error still persists.

However, we are not able to replicate this problem on our test GSuite domain. We tried couple of options using same SA as the client:

  1. The impersonated account hasn't permissions to access the resource. This result in:

googleapiclient.errors.HttpError: https://www.googleapis.com/admin/directory/v1/users?customer=my_customer&alt=json returned "Not Authorized to access this resource/api">

  1. The scopes are just partial:

google.auth.exceptions.RefreshError: ('access_denied: Requested client not authorized.', '{\n "error": "access_denied",\n "error_description": "Requested client not authorized."\n}')

  1. The 'Enabled API Access' is not checked.

googleapiclient.errors.HttpError: https://www.googleapis.com/admin/directory/v1/users?customer=my_customer&alt=json returned "Domain cannot use apis.">

  1. The error we are receiving from the client("Client is unauthorized to retrieve access tokens using this method."), we are able to replicate only if the client_id is not in the list of authenticated clients at all. But we are sure, the problematic GSuite domains have the SA authenticated in "Manage API client access" page.

We are using these scopes: https://www.googleapis.com/auth/userinfo.profile,https://www.googleapis.com/auth/userinfo.email,https://www.googleapis.com/auth/gmail.readonly,https://www.googleapis.com/auth/plus.login,https://www.googleapis.com/auth/calendar.readonly,https://www.googleapis.com/auth/contacts.readonly, https://www.googleapis.com/auth/admin.directory.user.readonly

Do you have any ideas how to debug/solve this issue?

2

2 Answers

2
votes

Here is what you need to do. Double check each step. If in doubt, start over.

  1. Enable "Admin SDK API. This is enabled on a per project basis.
  2. Create a service account. Do not add or remove any privileges. Don't change the service account in any way. If you do you will get an error that you are not authorized.
  3. Enable Domain-wide Delegation on the service account.
  4. Follow this document to delegate domain-wide authority to your service account:

Delegate domain-wide authority to your service account

  1. When creating the service account credentials (from the downloaded Json) you will need the following scopes for full G Suite management:

    "https://www.googleapis.com/auth/admin.directory.group", "https://www.googleapis.com/auth/admin.directory.user"

  2. Impersonate a user account which creates new credentials. The user account needs to be a G Suite superadmin. This account must have logged into G Suite at least once and accepted the Terms of Service.

  3. Create your client using the credentials from step #5.

Working Python Example:

from googleapiclient.discovery import build
from google.oauth2 import service_account

# This is the service account credentials file
credentials_file = 'google-directory-api.json'

# In this example I only need to send email
credentials = service_account.Credentials.from_service_account_file(
                credentials_file,
                scopes=['https://www.googleapis.com/auth/gmail.send'])

# This user is a G Suite superadmin
impersonate = '[email protected]'

credentials = credentials.with_subject(impersonate)

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

I think we are going to need to take this in stages. Lets start with your first error and see if that fixes your issue.

Background info

There are several types of clients that you can create in Google developer console. Here are the top three.

  • Browser client: Used for web applications
  • Native client (other): used for installed desktop applications
  • Service account: used for server to server communication.

The clients are different the client.json file you download is different and the code used to authenticated to the authentication server is also different.

Error 1: code / client missmatch

unauthorized_client: Client is unauthorized to retrieve access tokens using this method.

Can mean one of two things. Either you have created a service account client and you are not using service account code to authenticate or you are are using the code to authenticate with a service account but you have not created a service account client. You haven't posted what language you are using or any code so I cant tell you if the code you are using is intended to be used with a service account or not. Your going to have to look into this one a bit.

Check in developer console make sure your client is like this If it is check your code. If it isnt then create a real service account client and try again.

enter image description here