I'm trying to authenticate users to my site with their Office 365 accounts, so I have been following the guidance on using the OWIN OpenID Connect middleware to add authentication and successfully managed to authenticate and retrieve their profile.
I am now trying to get the email address of the user (so I can populate their system account with their contact details), but I can't seem to get an email claim back. I have tried making a request using the scope openid profile email
, but the claim-set does not contain any mail information.
Is there a way to get the email of a user from Azure AD via the OpenID Connect endpoint?
I struggled with the same problem for a few days before arriving at a solution. In answer to your question: yes, you should be able to get the e-mail address back in your claims as long as you:
profile
or email
scope in your request, andNote that the e-mail address may not be returned in an email
claim: in my case (once I got it working) it's coming back in a name
claim.
However, not getting the e-mail address back at all could be caused by one of the following issues:
As per this guide to Scopes, permissions, and consent in the Azure Active Directory v2.0 endpoint, even if you include the email
scope you may not get an e-mail address back:
The
If you're getting other profile-related claims back (like given_name
and family_name
), this might be the problem.
This was the cause for me. I wasn't getting any profile-related claims back (first name, last name, username, e-mail, etc.).
In my case, the identity-handling stack looks like this:
The problem was in the IdentityServer3.AspNetIdentity AspNetIdentityUserService
class: the InstantiateNewUserFromExternalProviderAsync()
method looks like this:
protected virtual Task<TUser> InstantiateNewUserFromExternalProviderAsync(
string provider,
string providerId,
IEnumerable<Claim> claims)
{
var user = new TUser() { UserName = Guid.NewGuid().ToString("N") };
return Task.FromResult(user);
}
Note it passes in a claims collection then ignores it. My solution was to create a class derived from this and override the method to something like this:
protected override Task<TUser> InstantiateNewUserFromExternalProviderAsync(
string provider,
string providerId,
IEnumerable<Claim> claims)
{
var user = new TUser
{
UserName = Guid.NewGuid().ToString("N"),
Claims = claims
};
return Task.FromResult(user);
}
I don't know exactly what middleware components you're using, but it's easy to see the raw claims returned from your external provider; that'll at least tell you they're coming back OK and that the problem is somewhere in your middleware. Just add a Notifications
property to your OpenIdConnectAuthenticationOptions
object, like this:
// Configure Azure AD as a provider
var azureAdOptions = new OpenIdConnectAuthenticationOptions
{
AuthenticationType = Constants.Azure.AuthenticationType,
Caption = Resources.AzureSignInCaption,
Scope = Constants.Azure.Scopes,
ClientId = Config.Azure.ClientId,
Authority = Constants.Azure.AuthenticationRootUri,
PostLogoutRedirectUri = Config.Identity.RedirectUri,
RedirectUri = Config.Azure.PostSignInRedirectUri,
AuthenticationMode = AuthenticationMode.Passive,
TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = false
},
Notifications = new OpenIdConnectAuthenticationNotifications
{
AuthorizationCodeReceived = context =>
{
// Log all the claims returned by Azure AD
var claims = context.AuthenticationTicket.Identity.Claims;
foreach (var claim in claims)
{
Log.Debug("{0} = {1}", claim.Type, claim.Value);
}
return null;
}
},
SignInAsAuthenticationType = signInAsType // this MUST come after TokenValidationParameters
};
app.UseOpenIdConnectAuthentication(azureAdOptions);