TransWikia.com

How to change google profile picture via API?

Stack Overflow Asked by h0x91B on December 25, 2021

I am looking for a way how to change user profile photo programmatically.

Generally, I need to be able to change avatars of domain GSuite users, but if there are API for changing my own avatar is also good.

Had tried already:

There are Contacts API, but I am trying to change my own (or impersonated one) profile image, so I believe this API isn’t for my case.

If you can point me in some direction to search I’ll be very glad. I just do not believe that there is no way to change avatar, it can’t be for real.

Update:

Checked Contact API – also doesn’t work, looks like it changes an avatar only on me in my contact list, nobody else doesn’t see changes, and the main profile picture remains the same.

Code:

// admin directory way
const { google } = require('googleapis');
const SafeBase64 = require('url-safe-base64');
const GOOGLE = require(process.env.GOOGLEAPIS_VAULT);

const encodedPhoto = SafeBase64.encode('R0lGODdhBAAEAIABAAMA/////ywAAAAABAAEAAACBkRiYJgHBQA7');

const JWTClient = new google.auth.JWT(
  GOOGLE.client_email,
  null,
  GOOGLE.private_key,
  [
    'https://www.googleapis.com/auth/admin.directory.user',
  ],
  'gsync@***.com', // sub
);

const directory = google.admin({ version: 'directory_v1', auth: JWTClient });
directory.users.photos.update({}, ctx.params.email);
const res = await directory.users.photos.update({
  userKey: ctx.params.email,
  resource: {
    photoData: encodedPhoto,
  },
});
// Contacts API way
const { google } = require('googleapis');
const SafeBase64 = require('url-safe-base64');
const GOOGLE = require(process.env.GOOGLEAPIS_VAULT);

const JWTClient = new google.auth.JWT(
  GOOGLE.client_email,
  null,
  GOOGLE.private_key,
  [
    'https://www.google.com/m8/feeds/',
  ],
  ctx.params.email, //sub
);

const res1 = await JWTClient.requestAsync({
  headers: {
    'GData-Version': 3.0,
  },
  params: {
    alt: 'json',
    q: 'arsenyp@***.com',
  },
  url: `https://www.google.com/m8/feeds/contacts/${ctx.params.email}/full`,
});

const contactIdFull = res1.data.feed.entry.filter((c) => c.gd$email[0].address === ctx.params.email)[0].id.$t;
const [, contactId] = //base/([a-z0-9]+)$/.exec(contactIdFull);

// https://www.google.com/m8/feeds/contacts/{userEmail}/full/{contactId}

const res2 = await JWTClient.requestAsync({
  headers: {
    'GData-Version': 3.0,
  },
  params: {
    alt: 'json',
  },
  url: `https://www.google.com/m8/feeds/contacts/${ctx.params.email}/full/${contactId}`,
});

const { href: image, gd$etag: etagJ } = res2.data.entry.link.filter((l) => l.rel === 'http://schemas.google.com/contacts/2008/rel#photo')[0];
const res3 = await axios({
  method: 'GET',
  url: image,
  headers: {
    Authorization: `Bearer "${(await JWTClient.getAccessTokenAsync()).token}"`,
  },
  responseType: 'arraybuffer',
});
const etag = JSON.parse(etagJ);

// PUT /m8/feeds/photos/media/default/contactId
// If-match: Etag
// Content-Type: image/*

const res4 = await axios({
  method: 'PUT',
  url: `https://www.google.com/m8/feeds/photos/media/default/${contactId}`,
  headers: {
    Authorization: `Bearer "${(await JWTClient.getAccessTokenAsync()).token}"`,
    'Content-Type': 'image/png',
  },
  // responseType: 'arraybuffer',
  data: Buffer.from('R0lGODdhBAAEAIABAAMA/////ywAAAAABAAEAAACBkRiYJgHBQA7', 'base64'),
});
// People API way (won't work, throwing an error)
const userId = '1024471xxxxx251564465';

const JWTClient = new google.auth.JWT(
  GOOGLE.client_email,
  null,
  GOOGLE.private_key,
  [
    'https://www.googleapis.com/auth/contacts',
    'profile',
  ],
  ctx.params.email, // sub
);

const people = google.people({ version: 'v1', auth: JWTClient });

const res = await people.people.updateContactPhoto({
  resourceName: `people/${userId}`,
  resource: {
    photoBytes: SafeBase64.encode('R0lGODdhBAAEAIABAAMA/////ywAAAAABAAEAAACBkRiYJgHBQA7'),
    personFields: 'photos',
  },
  sources: [
    'READ_SOURCE_TYPE_PROFILE',
  ],
});

One Answer

Ok, so as @Sudhakar mention there is no such API.

But I've found that admin directory API actually changes the profile in most places.

The trick in that the user needs manually once remove the avatar from https://aboutme.google.com/ Profile picture because this photo has top priority against admin directories one.

If the user removes the photo from aboutme.google.com then changes it via admin directory v1 API this photo is seen in the calendar, Gmail, contacts...

So check my first code sample:

// admin directory way
const { google } = require('googleapis');
const SafeBase64 = require('url-safe-base64');
const GOOGLE = require(process.env.GOOGLEAPIS_VAULT);

const encodedPhoto = SafeBase64.encode('R0lGODdhBAAEAIABAAMA/////ywAAAAABAAEAAACBkRiYJgHBQA7');
const targerUser = 'arsenyp@***.com';

const JWTClient = new google.auth.JWT(
  GOOGLE.client_email,
  null,
  GOOGLE.private_key,
  [
    'https://www.googleapis.com/auth/admin.directory.user',
  ],
  'gsync@***.com', // sub - this is service user with proper permissions, not a target user
);

const directory = google.admin({ version: 'directory_v1', auth: JWTClient });
directory.users.photos.update({}, targerUser);
const res = await directory.users.photos.update({
  userKey: targerUser,
  resource: {
    photoData: encodedPhoto,
  },
});

Answered by h0x91B on December 25, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP