darren
darren

Reputation: 587

Google user listing with service account using Python

I have a Json service file, and a service account that already accesses translate and sheets, but it will not access user lists. The result is either 400 showing its confused or 401 saying its not authorized. Examples are usually about client involved OAuth processes, where I need server to server. I have enabled that "Enable G Suite domain-wide delegation" feature on the service account too.

I read and tried the JWT method, but I get the same error responses. https://developers.google.com/identity/protocols/oauth2/service-account#python_2

My goal is to call either one of these end points https://www.googleapis.com/admin/directory/v1/users https://www.googleapis.com/admin/directory/v1/users.readonly

Any direction would be greatly appreciated.

UPDATE1: This is using the Jwt token approach which yields error 401.

with open(CLIENT_SECRET_FILE, "r+") as fh:
    config = json.load(fh)

iat = time.time()
exp = iat + 3600
payload = {'iss': config['client_email'],
           'sub': config['client_email'],
           'aud': 'https://www.googleapis.com/',
           'iat': iat,
           'exp': exp}
additional_headers = {'kid': config['private_key_id']}
signed_jwt = jwt.encode(payload, config['private_key'], headers=additional_headers,
                        algorithm='RS256')

url = 'https://www.googleapis.com/admin/directory/v1/users'        
headers = {"Authorization": "Bearer " + signed_jwt}
r = requests.get(url, headers=headers)

I have also tried

scopes = ['https://www.googleapis.com/auth/admin.directory.user']
credentials = ServiceAccountCredentials.from_json_keyfile_name(CLIENT_SECRET_FILE, scopes=scopes)
service = build('admin', 'directory_v1', credentials=credentials)
results = service.users().list().execute()

UPDATE2: This link has great information and simple code to review. As much as I tried to avoid impersonation, the AdminSDK requires it. That makes integrations a bit awkward in my view. In addition, the issue I also faced was the Domain-Wide-Delegation screen in the Google Workspace Admin can get messed up. Deleting the entry and recreating it fixed the forever 403 error I kept getting no matter what I had tried. https://gist.github.com/lewisrodgers/fa766ebd37c1397d3a014eb73805edd1

Upvotes: 3

Views: 1868

Answers (2)

darren
darren

Reputation: 587

The link below has great information and simple code to review. As much as I tried to avoid impersonation, the AdminSDK requires it. That makes integrations a bit awkward in my view.

In addition, the issue I also faced was the Domain-Wide-Delegation screen in the Google Workspace Admin that messed up. After much digging over weeks, I found a simple solution of deleting and recreating the client entry in that screen. It fixed the never ending 403 error that hit every test I tried that should have worked and did for many others.

This seems to be the only API set by Google that requires impersonation, and is annoying when attempting to create a SaaS solution.

Really basic, trimmed examples, and decent article references. https://gist.github.com/lewisrodgers/fa766ebd37c1397d3a014eb73805edd1

Upvotes: 0

ziganotschka
ziganotschka

Reputation: 26806

You need to incorporate into your code impersonation, so that the service account acts on behalf of the admin

Because only admins have authroization to access Resource: users.

For impersonation in Python you need to implement the additional line

delegated_credentials = credentials.with_subject('[email protected]')

Upvotes: 3

Related Questions