Google Admin SDK: Get a list of groups that a user belongs to
Asked Answered
B

5

7

I see that it is possible to list all members that belong to a specific group, as documented here:

https://developers.google.com/admin-sdk/directory/v1/guides/manage-group-members#get_all_members

But is it possible to get a list of groups that a user belongs to? I was hoping that Users.get would contain this information, or the Members API would have something similar, but I don't see it.

Baca answered 11/6, 2014 at 2:59 Comment(0)
B
10

So I've found the solution in the Developer Guide, although it does not exist in the API documentation!!

https://developers.google.com/admin-sdk/directory/v1/guides/manage-groups#get_all_member_groups

Baca answered 11/6, 2014 at 16:29 Comment(0)
D
2

The suggestions to use the Admin API will work - but access to that API requires admin permissions. I've used a service account in the past, but that's not a great practice.

If you just want to make an API call to get a users's groups using the user's oauth token, you can use the Cloud Identity API - specifically groups.membership.searchTransitiveGroups: https://cloud.google.com/identity/docs/reference/rest/v1/groups.memberships/searchTransitiveGroups

Here is some Ruby code to help explain:

token = # oauth token
email = # email address of authenticated user
url = "https://cloudidentity.googleapis.com/v1/groups/-/memberships:searchTransitiveGroups"
params =  { query: "member_key_id == '#{email}' && 'cloudidentity.googleapis.com/groups.discussion_forum' in labels" }
headers = { Authorization: "Bearer #{token}" }
response = Faraday.get(url, params, headers)
group_list = JSON.parse(response.body).dig('memberships').map{|m| m.dig('groupKey','id')}

Dowager answered 11/4, 2023 at 1:50 Comment(1)
As of April 27th, 2024, I am pretty sure this API endpoint is broken. If I use the directMember groups, everything works fine. However, if I use searchTransitiveGroups, I get an error 400, invalid parameter when there is no invalid parameter. If you see this, I'd be curious to know if you can replicate it. To anyone in the future, as far as I know, this endpoint gives you a 400, even if you don't have an invalid parameter.Briannabrianne
R
0

The best way to achieve this is by using the google admin sdk api.

groups.list()

groups.list() with details

For example if you want to do it using the python sdk, you can use the following

from __future__ import print_function
import logging
import os.path
import csv
import json
from googleapiclient.discovery import build
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials

# If modifying these scopes, delete the file token.json.
### https://developers.google.com/admin-sdk/directory/v1/guides/authorizing
### https://developers.google.com/admin-sdk/directory/v1/quickstart/python
SCOPES = ['https://www.googleapis.com/auth/admin.directory.user',
          'https://www.googleapis.com/auth/admin.directory.group']


"""
########################################################################################################################################################
# Logging level set for the script
# https://realpython.com/python-logging/
########################################################################################################################################################
"""
logging.basicConfig(level=logging.INFO)

class GSuite_management(object):
  """
  ########################################################################################################################################################
  # GSuite_management CLASS
  #  --> This class will have methods to manage the memebers of organization using Gsuite Admin SDK
  ########################################################################################################################################################
  """

  service = None

  def __init__(self):
      """
      GSuite_management Constrouctor
      """
      creds = None
      # The file token.json stores the user's access and refresh tokens, and is
      # created automatically when the authorization flow completes for the first
      # time.
      if os.path.exists('token.json'):
          creds = Credentials.from_authorized_user_file('token.json', SCOPES)
      # If there are no (valid) credentials available, let the user log in.
      if not creds or not creds.valid:
          if creds and creds.expired and creds.refresh_token:
              creds.refresh(Request())
          else:
              flow = InstalledAppFlow.from_client_secrets_file(
                  'credentials.json', SCOPES)
              creds = flow.run_local_server(port=0)
          # Save the credentials for the next run
          with open('token.json', 'w') as token:
              token.write(creds.to_json())  
      self.service = build('admin', 'directory_v1', credentials=creds)          

  def list_all_groups_a_user_is_a_part_of(self, userEmail):
    """
    This method will list all the groups a user is a part of and return them as a list
    """
    listOfEmailGroups=[]
    try:
      results = self.service.groups().list(domain="yourdomain.com",userKey=userEmail, maxResults=400).execute()
      logging.debug(results)
      groups = results.get('groups', [])
      if not groups:
          print('No groups in the domain.')
      else:
          for group in groups:
            logging.info(u'{0} {1} {2}'.format(group['email'],group['name'], group['directMembersCount']))
            listOfEmailGroups.append(group['email'])
    except Exception as e:
      logging.error("Exiting!!!")
      SystemExit(e) 
    return listOfEmailGroups
Rimmer answered 10/11, 2021 at 13:16 Comment(0)
G
0

We can use any google-admin-sdk library like google-api-nodejs-client to query groups of a particular user

This method is using GET https://admin.googleapis.com/admin/directory/v1/groups?userKey=userkey endpoint linked in jekennedy's answer

/**
 * Retrieve all groups for a member
 *
 * @param {google.auth.OAuth2} auth An authorized OAuth2 client.
 * @param {string} userEmail primary email of the user
 */
function listGroupsOfMember(auth, userEmail) {
  const admin = google.admin({version: 'directory_v1', auth});
  admin.groups.list({
    userKey: userEmail,
    maxResults: 10,
    orderBy: 'email',
  }, (err, res) => {
    if (err) {
      console.log(err)
      return console.error('The API returned an error:', err.message);
    }
    const groups = res.data.groups;
    if (groups.length) {
      console.log('Groups:');
      groups.forEach((group) => {
        console.log(group);
      });
    } else {
      console.log('No groups found.');
    }
  });
}

Example usage:

const {google} = require('googleapis');
const path = require('path');


// acquire an authentication client using a service account
const auth = await google.auth.getClient({
  keyFile: path.join(__dirname, '../serviceaccount.json'),
  scopes: [
    'https://www.googleapis.com/auth/admin.directory.user',
    'https://www.googleapis.com/auth/admin.directory.group',
  ],
});
// impersonate super admin
auth.subject = "[email protected]"

listGroupsOfMember(auth, "[email protected]")
Glycosuria answered 12/8, 2022 at 9:53 Comment(0)
G
0

If you are using Node.Js you can install this library:

googleapis@105 @google-cloud/[email protected]

With this command for example:

yarn add googleapis@105 @google-cloud/[email protected]

Then you can use a script like this one which uses a recursive function to find all groups to which a user belongs:

const fs = require('fs').promises;
const {authenticate} = require('@google-cloud/local-auth');
const path = require('path');
const {google} = require('googleapis');

const SCOPES = [
  'https://www.googleapis.com/auth/admin.directory.group.member.readonly',
  'https://www.googleapis.com/auth/admin.directory.group.readonly'
];
const CREDENTIALS_PATH = path.join(process.cwd(), '../client_secret_165820051388-0058a80cn1kgh4uk0ediif68t9m9n2ou.apps.googleusercontent.com.json');
const TOKEN_PATH = path.join(process.cwd(), 'token.json');


/**
 * Reads previously authorized credentials from the save file.
 *
 * @return {Promise<OAuth2Client|null>}
 */
async function loadSavedCredentialsIfExist() {
  try {
    const content = await fs.readFile(TOKEN_PATH);
    const credentials = JSON.parse(content);
    return google.auth.fromJSON(credentials);
  } catch (err) {
    return null;
  }
}

/**
 * Serializes credentials to a file comptible with GoogleAUth.fromJSON.
 *
 * @param {OAuth2Client} client
 * @return {Promise<void>}
 */
async function saveCredentials(client) {
  const content = await fs.readFile(CREDENTIALS_PATH);
  const keys = JSON.parse(content);
  const key = keys.installed || keys.web;
  const payload = JSON.stringify({
    type: 'authorized_user',
    client_id: key.client_id,
    client_secret: key.client_secret,
    refresh_token: client.credentials.refresh_token,
  });
  await fs.writeFile(TOKEN_PATH, payload);
}

/**
 * Load or request or authorization to call APIs.
 *
 */
async function authorize() {
  let client = await loadSavedCredentialsIfExist();
  if (client) {
    return client;
  }
  client = await authenticate({
    scopes: SCOPES,
    keyfilePath: CREDENTIALS_PATH,
  });
  if (client.credentials) {
    await saveCredentials(client);
  }
  return client;
}

/**
 * Lists all groups of a user recursively.
 *
 * @param {google.auth.OAuth2} auth An authorized OAuth2 client.
 * @oaram {string} userKey The user email
 */
async function listUsers(auth, userKey) {
  const service = google.admin({version: 'directory_v1', auth});
  const accumulatedGroups = []
  const MAX_RESULTS = 5
  const orderBy = 'email'
  const res = await service.groups.list({
    userKey,
    maxResults: MAX_RESULTS,
    orderBy
  });

  const { groups, nextPageToken } = res.data
  let pageToken = nextPageToken
  if(!!groups) {
    accumulatedGroups.push(...groups)
  }
  while(!!pageToken) {
    const res = await service.groups.list({
      userKey,
      maxResults: MAX_RESULTS,
      pageToken,
      orderBy
    });
    const { groups, nextPageToken } = res.data
    pageToken = nextPageToken
    accumulatedGroups.push(...groups)
  }
  if(accumulatedGroups.length === 0) {
    return []
  }
  return [
    ...(await Promise.all(accumulatedGroups.map(g => g.email).map(e => listUsers(auth, e))))
      .flatMap(a => a),
    ...accumulatedGroups
  ]
}

authorize()
.then((client) => {
  console.log("Authentication saved")
  return listUsers(client, '[email protected]')
}).then(groups => {
  groups.forEach(g => console.log(g.email))
}).catch(console.error)

This script will print out all emails of all groups to which a user with a specific email belongs. However make sure you have the right permissions for the user which created the Google App for which the Oauth credentials were generated. Otherwise you will get a 403 error.

Genova answered 24/4, 2023 at 15:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.