How to display user's image in Microsoft Graph using python
Question:
I tried using
GET https://graph.microsoft.com/v1.0/me/photo/$value
to get the user’s image/photo but it only returns an HTTP 200 status code. How can I get the binary data?
I’ve also tried using the content.property as suggested in a similar post but get a .format
is not an attribute of the dict.
@app.route("/photo")
def get_photo():
token = _get_token_from_cache(app_config.SCOPE)
if not token:
return redirect(url_for("login"))
photo = requests.get(app_config.PHOTO_ENDPOINT,
headers={'Authorization': 'Bearer ' + token['access_token']})
print(photo.status_code)
return photo
Answers:
Gets a profile photo, and optionally saves a local copy. Returns a tuple of the raw photo data, HTTP status code, content type, and saved filename. Refer to this sample.
def profile_photo(session, *, user_id='me', save_as=None):
"""Get profile photo, and optionally save a local copy.
session = requests.Session() instance with Graph access token
user_id = Graph id value for the user, or 'me' (default) for current user
save_as = optional filename to save the photo locally. Should not include an
extension - the extension is determined by photo's content type.
Returns a tuple of the photo (raw data), HTTP status code, content type, saved filename.
"""
endpoint = 'me/photo/$value' if user_id == 'me' else f'users/{user_id}/$value'
photo_response = session.get(api_endpoint(endpoint),
stream=True)
photo_status_code = photo_response.status_code
if photo_response.ok:
photo = photo_response.raw.read()
# note we remove /$value from endpoint to get metadata endpoint
metadata_response = session.get(api_endpoint(endpoint[:-7]))
content_type = metadata_response.json().get('@odata.mediaContentType', '')
else:
photo = ''
content_type = ''
if photo and save_as:
extension = content_type.split('/')[1]
filename = save_as + '.' + extension
with open(filename, 'wb') as fhandle:
fhandle.write(photo)
else:
filename = ''
return (photo, photo_status_code, content_type, filename)
Alternate approach, based on the original question’s code, if you want to display the resulting image on a web page.
from base64 import b64encode
@app.route("/photo")
def get_photo():
token = _get_token_from_cache(app_config.SCOPE)
if not token:
return redirect(url_for("login"))
response = requests.get(
app_config.PHOTO_ENDPOINT,
headers={'Authorization': 'Bearer ' + token['access_token']}
)
content_type = response.raw.getheader('Content-Type')
return render_template('index.html',
photo_data=b64encode(response.content),
photo_content_type=content_type)
Then in the index.html
template you can display the photo like so:
<html>
<body>
<img src="data:{{ photo_content_type }};base64,{{ photo_data }}" />
</body>
</html>
Call Api: -
Axios.get('https://graph.microsoft.com/v1.0/me/photo/$value', {
headers: { 'Authorization': 'Bearer '+AccessToken },
responseType: 'blob'
}).then(o => {
const url = window.URL || window.webkitURL;
const blobUrl = url.createObjectURL(o.data);
self.setState({ imageUrl: blobUrl });
})
JSX: -
<img alt="image" src={this.state.imageUrl} />
Here is what worked for me:
from base64 import b64encode
token = _get_token_from_cache(app_config.graphSCOPE)
aadPhotoURI = "https://graph.microsoft.com/v1.0/me/photo/$value"
response = requests.get(aadPhotoURI, headers={'Authorization': 'Bearer ' +
token['access_token']},)
content_type = response.raw.getheader('Content-Type')
return render_template(
'usersettings.html',
photo_data = b64encode(response.content).decode(),
photo_content_type = content_type)
then in the .html page added:
<img class="account-img" alt="" src="data:{{ photo_content_type }};base64,{{ photo_data }}"/>
CSS for account-img:
.account-img {
width: 40px;
float: right;
border-radius: 50%;
}
I tried using
GET https://graph.microsoft.com/v1.0/me/photo/$value
to get the user’s image/photo but it only returns an HTTP 200 status code. How can I get the binary data?
I’ve also tried using the content.property as suggested in a similar post but get a .format
is not an attribute of the dict.
@app.route("/photo")
def get_photo():
token = _get_token_from_cache(app_config.SCOPE)
if not token:
return redirect(url_for("login"))
photo = requests.get(app_config.PHOTO_ENDPOINT,
headers={'Authorization': 'Bearer ' + token['access_token']})
print(photo.status_code)
return photo
Gets a profile photo, and optionally saves a local copy. Returns a tuple of the raw photo data, HTTP status code, content type, and saved filename. Refer to this sample.
def profile_photo(session, *, user_id='me', save_as=None):
"""Get profile photo, and optionally save a local copy.
session = requests.Session() instance with Graph access token
user_id = Graph id value for the user, or 'me' (default) for current user
save_as = optional filename to save the photo locally. Should not include an
extension - the extension is determined by photo's content type.
Returns a tuple of the photo (raw data), HTTP status code, content type, saved filename.
"""
endpoint = 'me/photo/$value' if user_id == 'me' else f'users/{user_id}/$value'
photo_response = session.get(api_endpoint(endpoint),
stream=True)
photo_status_code = photo_response.status_code
if photo_response.ok:
photo = photo_response.raw.read()
# note we remove /$value from endpoint to get metadata endpoint
metadata_response = session.get(api_endpoint(endpoint[:-7]))
content_type = metadata_response.json().get('@odata.mediaContentType', '')
else:
photo = ''
content_type = ''
if photo and save_as:
extension = content_type.split('/')[1]
filename = save_as + '.' + extension
with open(filename, 'wb') as fhandle:
fhandle.write(photo)
else:
filename = ''
return (photo, photo_status_code, content_type, filename)
Alternate approach, based on the original question’s code, if you want to display the resulting image on a web page.
from base64 import b64encode
@app.route("/photo")
def get_photo():
token = _get_token_from_cache(app_config.SCOPE)
if not token:
return redirect(url_for("login"))
response = requests.get(
app_config.PHOTO_ENDPOINT,
headers={'Authorization': 'Bearer ' + token['access_token']}
)
content_type = response.raw.getheader('Content-Type')
return render_template('index.html',
photo_data=b64encode(response.content),
photo_content_type=content_type)
Then in the index.html
template you can display the photo like so:
<html>
<body>
<img src="data:{{ photo_content_type }};base64,{{ photo_data }}" />
</body>
</html>
Call Api: -
Axios.get('https://graph.microsoft.com/v1.0/me/photo/$value', {
headers: { 'Authorization': 'Bearer '+AccessToken },
responseType: 'blob'
}).then(o => {
const url = window.URL || window.webkitURL;
const blobUrl = url.createObjectURL(o.data);
self.setState({ imageUrl: blobUrl });
})
JSX: -
<img alt="image" src={this.state.imageUrl} />
Here is what worked for me:
from base64 import b64encode
token = _get_token_from_cache(app_config.graphSCOPE)
aadPhotoURI = "https://graph.microsoft.com/v1.0/me/photo/$value"
response = requests.get(aadPhotoURI, headers={'Authorization': 'Bearer ' +
token['access_token']},)
content_type = response.raw.getheader('Content-Type')
return render_template(
'usersettings.html',
photo_data = b64encode(response.content).decode(),
photo_content_type = content_type)
then in the .html page added:
<img class="account-img" alt="" src="data:{{ photo_content_type }};base64,{{ photo_data }}"/>
CSS for account-img:
.account-img {
width: 40px;
float: right;
border-radius: 50%;
}