The user profile returned from an Azure AD connection does not include the user’s picture, but I see a photo is available in Azure. Is it possible to get it?
Also, the profile does not include the user’s manager or direct reports, even when checking the Extended attributes option in the global configuration for Azure AD connections.
Auth0 does not, by default, return either the picture nor the direct reports/managers for Azure AD profiles.
The user picture is not directly available because Azure AD provides it directly as a stream of bytes instead of giving an URL for the picture as other identity providers do. Auth0 uses the URL model for the picture
property of the normalized user profile, so the content provided by Azure can’t be directly translated.
The direct reports and managers are also not available directly because they are not part of the profile returned by Azure’s Graph API. They are returned as navigational properties and must be requested separately.
Those properties can be retrieved with a rule and put in the user profile, with code like this:
function (user, context, callback) {
// only do this for users from Azure AD
// or maybe for a specific connection
if (user.identities[0].provider !== 'waad')
return callback(null, user, context);
// To call Azure's Graph API we need an access token
// The access token can be either
// - The access token given to the logged in user by the IdP (provided that it has
// the necessary permissions)
// - An access token obtained through the client credentials grant (
// using the same client_id/key configured for the Azure AD connection,
// or a new set of credentials, obtained specifically for this).
// for simplicity, we will use the user's IdP access token
var aad_access_token = user.identities[0].access_token;
// call Azure's graph api to get information about the user
var baseUrl = 'https://graph.windows.net/'+ user.tenantid + '/users/'+ user.oid;
console.log('baseUrl:' + baseUrl);
var apiRequest = function(segment, nullEncoding, callback) {
var options = {
url: baseUrl + '/' + segment + '?api-version=1.6',
headers: {
'Authorization': 'Bearer ' + aad_access_token
}
};
if (nullEncoding) {
options.encoding = null;
}
console.log('Requesting to '+ options.url);
request(options, function(err, response, body){
if (err) {
console.log("Error when calling "+ options.url);
console.log(err);
}
callback(err, response, body);
});
};
var getThumbnail = function(cb) {
apiRequest('thumbnailPhoto', true, function(err, response, body) {
if (!err && response.statusCode === 200) {
user.thumbnailPhoto = "data:" + response.headers"content-type"] + ";base64," + new Buffer(body).toString('base64');
}
cb(err);
});
};
var getManager = function(cb) {
apiRequest('manager', false, function(err, response, body) {
if (!err && response.statusCode === 200) {
var manager = JSON.parse(body);
user.manager = manager.displayName;
}
cb(err);
});
};
var getDirectReports = function(cb) {
apiRequest('directReports', false, function(err, response, body) {
if (!err && response.statusCode === 200) {
user.directReports = ];
var directReports = JSON.parse(body).value;
directReports.forEach(function(person) {
user.directReports.push(person.displayName);
});
}
cb(err);
});
};
getThumbnail(function(err) {
getManager(function(err) {
getDirectReports(function(err) {
callback(null, user, context);
});
});
});
}
This rule calls Azure AD’s Graph API to get sets three properties in the profile: thumbnailPhoto
, manager
and directReports
. If you want to persist those properties so that future calls to /api/v2/users
will get the information, you can do so by updating the user’s app_metadata
after retrieving the values:
// ...] put the following code before calling the callback at the end
// save the values in app_metadata before returning
user.app_metadata = user.app_metadata || {};
user.app_metadata.manager = user.manager;
user.app_metadata.directReports = user.directReports;
user.app_metadata.thumbnailPhoto = user.thumbnailPhoto;
// persist the app_metadata update
auth0.users.updateAppMetadata(user.user_id, user.app_metadata)
.then(function(){
callback(null, user, context);
})
.catch(function(err){
callback(err);
});