Reputation: 1359
I am able to get access to a user's accessToken, and am making a call to GET https://graph.microsoft.com/v1.0/me
with an Authorization: Bearer <token>
header.
However, in the response body I'm getting something like this:
{
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#users",
"value": [
{
"givenName": "Foo",
"surname": "Bar",
"displayName": "Foo Bar",
"id": "b41efha115adcca29",
"userPrincipalName": "[email protected]",
"businessPhones": [],
"jobTitle": null,
"mail": null,
"mobilePhone": null,
"officeLocation": null,
"preferredLanguage": null
}
]
}
The mail
property is null
, and the userPrincipalName
in this response body happens to the be the user's email address. However, there's this from Microsoft's docs:
Although the UPN and email share the same format, the value of the UPN for a user might or might not be the same as the email address of the user.
When initiating the login request of the user, we're requesting for the "user.read"
and "email"
scopes. We're using the MSAL.js library to obtain the access token, and our code reads something like this:
login (): ng.IPromise<IMicrosoftOAuthResponse> {
const prom = this.userAgentApplication.loginPopup(["user.read", "email"])
.then((idToken) => {
return this.userAgentApplication.acquireTokenSilent(["user.read", "email"]);
})
.then((accessToken) => {
// at this point, we have the accessToken and make a call to the graph api
});
return this.$q.when(prom);
}
How do I get the actual email address of the user here?
Upvotes: 13
Views: 22499
Reputation: 159
I ran into this recently myself, getting an error when trying to access https://graph.microsoft.com/v1.0/me
:
requests.exceptions.HTTPError: 403 Client Error: Forbidden for url: https://graph.microsoft.com/v1.0/me | Error Message: Exception of type 'Microsoft.Fast.Profile.Core.Exception.ProfileAccessDeniedException' was thrown.
How I got around it:
I used the returned id_token included in the access token. You might not always receive this, for example the MSAL library may not always return this if simply refreshing an access token, so you should probably have a copy of it stored somewhere if you don't extract and save the id_token's information when you first get it.
The id_token is base64 encoded per the standard, which for debugging you can use this tool to figure out the right details: https://jwt.io/#debugger
I used this library to reliably decode the token: https://github.com/jpadilla/pyjwt/
pip install PyJWT
from jwt import decode
id_token = '' # Replace this with the id_token provided to you when getting the access token
decoded_id_token = decode(id_token, algorithms=['RS256'], options={'verify_signature': False})
user_email = decoded_id_token.get('email') if decoded_id_token.get('email') else decoded_id_token.get('preferred_username')
Upvotes: 0
Reputation: 21
var user = graphServiceClient.Users[UserId].Request().Select(x=>x.Identities).GetAsync();
var email = user.Identities.FirstOrDefault().IssuerAssignedId;
Upvotes: 1
Reputation: 2681
For me, https://graph.microsoft.com/v1.0/users/<userid>/authentication/emailMethods
endpoint worked. For this, the client must have UserAuthenticationMethod.Read.All
permission. One can find more documentation here.
Sample reponse:
{
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#users('8225f1cd-8025-4f8b-bf94-c595e02e3403')/authentication/emailMethods",
"value": [
{
"id": "3ddfcfc8-9383-446f-83cc-3ab9be4be18f",
"emailAddress": "[email protected]"
}
]
}
Upvotes: 0
Reputation: 121
Even though this is an old question, I thought I would share my solution to getting the email of a signed-in user. Be aware that this solution requires access to the user's id_token
.
The response from calling the /me
endpoint looks as follows:
Object {
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#users/$entity",
"businessPhones": Array [],
"displayName": "John Doe",
"givenName": "John",
"id": "xxxxxx",
"jobTitle": null,
"mail": null,
"mobilePhone": null,
"officeLocation": null,
"preferredLanguage": null,
"surname": "Doe",
"userPrincipalName": "johndoe_gmail.com#EXT#@johndoegmail.onmicrosoft.com",
}
As we can see, the mail property of this response is null
. I am however able to get the user email by decoding the jwt id_token
passed along with the access_token
when calling the /token
endpoint.
By applying the decodeJwtToken() function (attached at the end of this post) to the id_token, I am able to get the user email from the result
Object {
"aio": "xxxxxxxx",
"amr": Array [
"pwd",
],
"aud": "xxxxx",
"email": "[email protected]",
"exp": xxxxxx,
"family_name": "Doe",
"given_name": "John",
"iat": xxxxxx,
"idp": "live.com",
"ipaddr": "xxx.xxx.xxx.xxx",
"iss": "https://sts.windows.net/xxxx/",
"name": "John Doe",
"nbf": xxxx,
"nonce": "xxx",
"oid": "xxxxxxx",
"sub": "xxxxx",
"tid": "xxxxx",
"unique_name": "live.com#[email protected]",
"uti": "xxxx",
"ver": "1.0",
}
The decoding function looks as follows:
decodeIdToken = (token) => {
var base64Url = token.split('.')[1];
var base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
var jsonPayload = decodeURIComponent(Buffer.from(base64, 'base64').toString().split('').map(function(c) {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
}).join(''));
return JSON.parse(jsonPayload);
};
Upvotes: 1
Reputation: 27
create a trial account in microsoft office 365 business premium using the below link: https://signup.microsoft.com/Signup?OfferId=467eab54-127b-42d3-b046-3844b860bebf&dl=O365_BUSINESS_PREMIUM&culture=en-IN&country=IN&ali=1
Follow the steps while creating the account. It will allow us to create users in office 365. These users are like internal users of an organization. Now open azure portal with the above credential. All users of office 365 will be imported in active azure directory.
Now register an application with Read users basic profile delegated permission in active azure directory. note down client id , client secret and tenant domain to get access token for service to service authentication. This access token can be used to get user records which will be containing mail field as [email protected]
Upvotes: -1
Reputation: 5838
The mail
property is set in one of 2 ways:
mail
property is set for this licensed user.If the user does not have an O365 mailbox/license, you could also search for the user by userPrincipalName, displayName, etc. $filter supports the OR operator.
Hope this helps,
Upvotes: 6