RichW
RichW

Reputation: 469

how to get user's image using Microsoft Graph API, encoding issue?

Having a look into Microsoft's Graph API, specifically looking at the angular example called 'O365-Angular-Microsoft-Graph-Connect' - https://github.com/OfficeDev/O365-Angular-Microsoft-Graph-Connect. Have successfully registered the app and installed the dependencies. However when running the app I am correctly seeing all the user's details apart from the image, (all the users in our O365 tenancy have an image). Debugging the app it appears the response received from the api is full of '�' symbols which suggests an encoding issue somewhere. When using the graph API explorer I get the image returned fine which suggests this is the app. Any ideas of how to remedy this so the example app works? The index html page is correctly UTF-8 encoded so the app looks correct to me which suggests an issue with the API, however as the graph API explorer gives me the correct image that suggests it's the app.

Any ideas on how to pull through the image in the example app provided by Microsoft?

Other thoughts are that as the example screenshot provided by MS uses a placeholder image this part of the app is simply not working yet.

Upvotes: 1

Views: 7355

Answers (5)

Kamlesh Kumar
Kamlesh Kumar

Reputation: 1680

Hope this helps: https://stackoverflow.com/a/69391807/3786343

In this answer, I've used angular current version 12 and microsoft graph api v1.0.

Upvotes: 0

Scott Johnson
Scott Johnson

Reputation: 1

Had the same issue all day!

Main points to consider

  • response.blob() Response.blob()
    *** The blob() method of the Response interface takes a Response stream and reads it to completion. It returns a promise that resolves with a Blob. ***
  • window.URL.createObjectURL(result) URL.createObjectURL()
    *** The new object URL represents the specified File object or Blob object. ***

When using a standard response such as Response.text() or Response.json() you will receive

SyntaxError: Unexpected token � in JSON at position 0

        fetch("https://graph.microsoft.com/v1.0/me/photo/$value", requestOptions)
          .then(response => response.blob())
          .then(result => setUserImage(window.URL.createObjectURL(result)))
          .catch(error => console.log('error', error));
 

Upvotes: 0

Paul
Paul

Reputation: 61

TypeScript code to get the photo

  @observable private photo: string;

    getPhoto('/me/photos/48x48/$value').then((photo) => {
      this.photo = photo;
    }).catch(error => {});
  }

<img className='br24' src={this.photo}/>

export function getPhoto(query: string): Promise<string> {
  let promise = new Promise<string>((resolve, reject) => {
    adalContext.AuthContext.acquireToken("https://graph.microsoft.com", (error, token) => {
      if (error) {
        reject(error);
      } else {
        if (query.indexOf('/') != 0)
          query = '/' + query;
        let u = `https://graph.microsoft.com/v1.0${query}`;
        axios.get(u, { headers: { Authorization: `Bearer ${token}`, encoding: null }, responseType: 'arraybuffer' }).then(
          val => {
            let photo = 'data:' + val.headers['content-type'] + ';base64,' + new Buffer(val.data, 'binary').toString('base64');
            resolve(photo);
          },
          error => {
            reject(error);
          }
        );
      }
    });
  });

  return promise;
}

Upvotes: 1

DGK
DGK

Reputation: 3015

This is an older question but I hope this will be helpful to some (C#).

Catch the incoming array as a byteArray and convert it to a base64string. These can easily be converted to images or saved in DB's

    public static async void GetPhoto(HttpClient client, string id)
    {
        var resp = await client.GetAsync(@"https://graph.microsoft.com/v1.0/users/" + id + "/photos/240x240/$value");

        var buffer = await resp.Content.ReadAsByteArrayAsync();
        var byteArray = buffer.ToArray();

        string base64String = Convert.ToBase64String(byteArray);
        if(base64String != null && base64String != "")
        {
            //Insert into database or convert.
        }
    }

Upvotes: 1

nettutvikler
nettutvikler

Reputation: 604

After playing with Postman (Chrome extension for playing with REST etc.) it is very clear that the returned image is ok and "normal" and that our code must make sure it is saved as it should be.

Afterwards I hacked this NodeJS code that can, maybe, help another newbies like me:)

/**
     /users/<id | userPrincipalName>/photo/$value
 */

function getUserPhoto(accessToken, userId, callback) {
          var options = {
            host: 'graph.microsoft.com',
            path: "/v1.0/users/" +userId + "/photo/$value",
            method: 'GET',
            headers: {
              Authorization: 'Bearer ' + accessToken
            }
          };

          https.get(options, function (response) {
            response.setEncoding('binary'); /* This is very very necessary! */
            var body = '';
            response.on('data', function (d) {
              body += d;
            });
            response.on('end', function () {
              var error;
              if (response.statusCode === 200) {
                    /* save as "normal image" */
                fs.writeFile('./public/img/image.jpeg', body, 'binary',  function(err){
                    if (err) throw err
                    console.log('Image saved ok')
                })
                /* callback - for example show in template as base64 image */
                callback(new Buffer(body, 'binary').toString('base64'));
              } else {
                error = new Error();
                error.code = response.statusCode;
                error.message = response.statusMessage;
                // The error body sometimes includes an empty space
                // before the first character, remove it or it causes an error.
                body = body.trim();
                error.innerError = JSON.parse(body).error;
                callback(error, null);
              }
            });
          }).on('error', function (e) {
            callback(e, null);
          });
        }

Upvotes: 1

Related Questions