I'm using dotnet core I want to setup a LinkedIn authentication on the site since there is no default authentication builder for LinkedIn as facebook, google and twitter I decided to use the generic implementation as follows:
services.AddAuthentication().AddOAuth("LinkedIn",
c =>
{
c.ClientId = Configuration["linkedin-app-id"];
c.ClientSecret = Configuration["linkedin-app-secret"];
c.Scope.Add("r_basicprofile");
c.Scope.Add("r_emailaddress");
c.CallbackPath = "/signin-linkedin";
c.AuthorizationEndpoint = "https://www.linkedin.com/oauth/v2/authorization";
c.TokenEndpoint = "https://www.linkedin.com/oauth/v2/accessToken";
c.UserInformationEndpoint = "https://api.linkedin.com/v1/people/~:(id,formatted-name,email-address,picture-url)";
})
I'm having an issue because GetExternalLoginInfoAsync() is null, looking the Identity ASP.net core source, is because the providerkey is null.
Taken from asp.net core code:
var providerKey = auth.Principal.FindFirstValue(ClaimTypes.NameIdentifier);
var provider = items["LoginProvider"] as string;
if (providerKey == null || provider == null)
{
return null;
}
the question is where can I add the ClaimTypes.NameIdentifier to the LinkedIn claim?
In this case, you have to pre populate each Claim manually using an OauthEvent like this:
.AddOAuth("LinkedIn",
c =>
{
c.ClientId = Configuration["linkedin-app-id"];
c.ClientSecret = Configuration["linkedin-app-secret"];
c.Scope.Add("r_basicprofile");
c.Scope.Add("r_emailaddress");
c.CallbackPath = "/signin-linkedin";
c.AuthorizationEndpoint = "https://www.linkedin.com/oauth/v2/authorization";
c.TokenEndpoint = "https://www.linkedin.com/oauth/v2/accessToken";
c.UserInformationEndpoint = "https://api.linkedin.com/v1/people/~:(id,formatted-name,email-address,picture-url)";
c.Events = new OAuthEvents
{
OnCreatingTicket = async context =>
{
var request = new HttpRequestMessage(HttpMethod.Get, context.Options.UserInformationEndpoint);
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", context.AccessToken);
request.Headers.Add("x-li-format", "json");
var response = await context.Backchannel.SendAsync(request, context.HttpContext.RequestAborted);
response.EnsureSuccessStatusCode();
var user = JObject.Parse(await response.Content.ReadAsStringAsync());
var userId = user.Value<string>("id");
if (!string.IsNullOrEmpty(userId))
{
context.Identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, userId, ClaimValueTypes.String, context.Options.ClaimsIssuer));
}
var formattedName = user.Value<string>("formattedName");
if (!string.IsNullOrEmpty(formattedName))
{
context.Identity.AddClaim(new Claim(ClaimTypes.Name, formattedName, ClaimValueTypes.String, context.Options.ClaimsIssuer));
}
var email = user.Value<string>("emailAddress");
if (!string.IsNullOrEmpty(email))
{
context.Identity.AddClaim(new Claim(ClaimTypes.Email, email, ClaimValueTypes.String,
context.Options.ClaimsIssuer));
}
var pictureUrl = user.Value<string>("pictureUrl");
if (!string.IsNullOrEmpty(pictureUrl))
{
context.Identity.AddClaim(new Claim("profile-picture", pictureUrl, ClaimValueTypes.String,
context.Options.ClaimsIssuer));
}
}
};
})
It is simpler to use NuGet package from AspNet.Security.OAuth.Providers and transform claims using options.ClaimActions.MapJsonKey
.AddLinkedIn(options =>
{
var linkedInOptions = new Dictionary<string, string>();
Configuration.Bind("LinkedIn", linkedInOptions);
options.ClientId = linkedInOptions[nameof(options.ClientId)];
options.ClientSecret = linkedInOptions[nameof(options.ClientSecret)];
// Use v2 API
options.AuthorizationEndpoint = "https://www.linkedin.com/oauth/v2/authorization";
options.TokenEndpoint = "https://www.linkedin.com/oauth/v2/accessToken";
// This is already mapped by NuGet package
//options.ClaimActions.MapJsonKey(OpenIdConnectConstants.Claims.Name, "formattedName");
See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers/blob/dev/src/AspNet.Security.OAuth.LinkedIn/LinkedInAuthenticationOptions.cs
Related
I am writing a method to get DisplayName of off ObjectID. Is there a quick way to figure out if the ObjectID is a Group Or an User Or a ServicePrincipal
Below is my weird\Rough method which is working for me. But I wanted to check if anyone has any simpler Or cooler solution.
I tried searching online for some solutions but no luck yet.
public static async Task<string> GetDisplayName(string TenantID, string ObjectID, string MSGraphToken, string ObjectType)
{
string DisplayNameURI = null;
string DisplayName = null;
var DisplayNamehttpClient = new HttpClient
{
BaseAddress = new Uri("https://graph.windows.net/")
};
if (ObjectType.Equals("Decide", StringComparison.OrdinalIgnoreCase))
{
// trying servicePrincipals
ObjectType = "servicePrincipals";
DisplayNameURI = $"{TenantID}/{ObjectType}/{ObjectID}?api-version=1.6";
var SPNhttpClient = new HttpClient
{
BaseAddress = new Uri("https://graph.windows.net/")
};
SPNhttpClient.DefaultRequestHeaders.Remove("Authorization");
SPNhttpClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + MSGraphToken);
HttpResponseMessage SPNResponse = await SPNhttpClient.GetAsync(DisplayNameURI).ConfigureAwait(false);
var SPNHttpsResponse = await SPNResponse.Content.ReadAsStringAsync();
dynamic SPNResult = JsonConvert.DeserializeObject<object>(SPNHttpsResponse);
DisplayName = SPNResult.displayName;
if (string.IsNullOrEmpty(DisplayName) == true)
{
// Trying for Users
ObjectType = "users";
DisplayNameURI = $"{TenantID}/{ObjectType}/{ObjectID}?api-version=1.6";
var usershttpClient = new HttpClient
{
BaseAddress = new Uri("https://graph.windows.net/")
};
usershttpClient.DefaultRequestHeaders.Remove("Authorization");
usershttpClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + MSGraphToken);
HttpResponseMessage usersResponse = await usershttpClient.GetAsync(DisplayNameURI).ConfigureAwait(false);
var usersHttpsResponse = await usersResponse.Content.ReadAsStringAsync();
dynamic usersResult = JsonConvert.DeserializeObject<object>(usersHttpsResponse);
DisplayName = usersResult.displayName;
if (string.IsNullOrEmpty(DisplayName) == true)
{
//Trying for Groups
ObjectType = "groups";
DisplayNameURI = $"{TenantID}/{ObjectType}/{ObjectID}?api-version=1.6";
var groupshttpClient = new HttpClient
{
BaseAddress = new Uri("https://graph.windows.net/")
};
groupshttpClient.DefaultRequestHeaders.Remove("Authorization");
groupshttpClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + MSGraphToken);
HttpResponseMessage groupsResponse = await groupshttpClient.GetAsync(DisplayNameURI).ConfigureAwait(false);
var groupsHttpsResponse = await groupsResponse.Content.ReadAsStringAsync();
dynamic groupsResult = JsonConvert.DeserializeObject<object>(groupsHttpsResponse);
DisplayName = groupsResult.displayName;
}
}
}
else
{
DisplayNameURI = $"{TenantID}/{ObjectType}/{ObjectID}?api-version=1.6";
DisplayNamehttpClient.DefaultRequestHeaders.Remove("Authorization");
DisplayNamehttpClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + MSGraphToken);
HttpResponseMessage DisplayNameResponse = await DisplayNamehttpClient.GetAsync(DisplayNameURI).ConfigureAwait(false);
var DisplayNameHttpsResponse = await DisplayNameResponse.Content.ReadAsStringAsync();
dynamic DisplayNameResult = JsonConvert.DeserializeObject<object>(DisplayNameHttpsResponse);
DisplayName = DisplayNameResult.displayName;
}
//Console.WriteLine($"{DisplayName}");
if (string.IsNullOrEmpty(DisplayName) == true)
{
DisplayName = "Unknown";
}
return DisplayName;
}
You can directly find the AD object based on objectID using PowerShell.
Command: Get-AzureADObjectByObjectId -ObjectIds objectID1,objected2
Reference: Get-AzureADObjectByObjectId (AzureAD) | Microsoft Docs
Otherwise you can using C# for calling graph api to get the details.
Code:
GraphServiceClient graphClient = new GraphServiceClient( authProvider );
var ids = new List<String>()
{
"objectID1",
"objectID2"
};
var types = new List<String>()
{
"user"
};
await graphClient.DirectoryObjects
.GetByIds(ids,types)
.Request()
.PostAsync();
Reference: directoryObject: getByIds - Microsoft Graph v1.0 | Microsoft Docs
I want to get my Azure B2C AD access token from the httpContext or similar, but I am using .NET framework 4.7.2. If I was using .Net core, I would use HttpContext.Authentication.GetTokenAsync() .
Background
I am using OpenIdConnect 4.1.0.
My OpenIdConnectAuthenticationOptions looks like this:
private OpenIdConnectAuthenticationOptions CreateOptionsFromSiteConfig(B2CConfig config)
{
OpenIdConnectAuthenticationOptions options = new OpenIdConnectAuthenticationOptions();
options.MetadataAddress = string.Format(_aadInstance, _tenant, config.Policy);
options.AuthenticationType = [B2CAD-POLICY-name];
options.AuthenticationMode = AuthenticationMode.Passive;
options.RedirectUri = config.AzureReplyUri;
options.PostLogoutRedirectUri = config.LogoutRedirectUri;
options.TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = "emails"
};
options.SaveTokens = true;
options.RedeemCode = true;
var identityProvider = GetIdentityProvider();
options.Notifications = new OpenIdConnectAuthenticationNotifications()
{
AuthenticationFailed = AuthenticationFailed,
RedirectToIdentityProvider = notification =>
{
return Task.FromResult(notification.ProtocolMessage.UiLocales = config.UiLocale ?? string.Empty);
},
SecurityTokenValidated = notification =>
{
notification.AuthenticationTicket.Identity.AddClaim(new Claim("idp", "azureadb2c"));
// transform all claims
ClaimsIdentity identity = notification.AuthenticationTicket.Identity;
notification.AuthenticationTicket.Identity.ApplyClaimsTransformations(new TransformationContext(FederatedAuthenticationConfiguration, identityProvider));
return Task.CompletedTask;
},
};
options.ClientId = config.ClientId;
options.Scope = "openid [api-scope-here]";
options.ResponseType = "id_token token";
return options;
}
There is multiple policies with the same name (i.e. multiple AuthenticationTypes with same name).
So far, I have found several suggestions, where the most promising one suggested:
var result = await owinContext.Authentication.AuthenticateAsync([B2CAD-POLICY-name]));
string token = result.Properties.Dictionary["access_token"];
However, the result is always NULL, eventhough I have verified that the b2cad policy is actually present in the OwinContext.
Any help is much appreciated!
Code is as follows
startup auth:
app.UseFacebookAuthentication(new FacebookAuthenticationOptions
{
AppId = "xxx",
AppSecret = "xxx",
BackchannelHttpHandler = new FacebookBackChannelHandler(),
UserInformationEndpoint = "https://graph.facebook.com/v2.4/me?fields=id,name,email,first_name,last_name,location",
Scope = { "email" }
});
in the accountcontroler RegisterExternal class i call the following:
var info = await AuthenticationManager_GetExternalLoginInfoAsync_WithExternalBearer();
Which is this class:
private async Task<ExternalLoginInfo> AuthenticationManager_GetExternalLoginInfoAsync_WithExternalBearer()
{
ExternalLoginInfo loginInfo = null;
var result = await Authentication.AuthenticateAsync(DefaultAuthenticationTypes.ExternalBearer);
if (result != null && result.Identity != null)
{
var idClaim = result.Identity.FindFirst(ClaimTypes.NameIdentifier);
if (idClaim != null)
{
loginInfo = new ExternalLoginInfo()
{
DefaultUserName = result.Identity.Name == null ? "" : result.Identity.Name.Replace(" ", ""),
Login = new UserLoginInfo(idClaim.Issuer, idClaim.Value),
};
}
}
return loginInfo;
}
This is because the RegisterExternal class on default will use authentication type cookie. Whenever i use it it will return null, so after surfing the web I've noticed it is necessary add this code which in turn will use the bearer for authentication, this will result in a reply where the username and the identity are no longer null, thus authorized. (see picture below)
Return object (username and login)
But, when i want to claim the email, i cannot do this. It will always return null no matter what i do.
I was running into the same issue and solved it by using the Facebook nuget package to get extra fields.
In my application I have implemented FacebookAuthenticationProvider and overridden the Authenticated(...) method with the following:
public class FacebookAuthProvider : FacebookAuthenticationProvider
{
public override Task Authenticated(FacebookAuthenticatedContext context)
{
var accessTokenClaim = new Claim("ExternalAccessToken", context.AccessToken, "urn:facebook:access_token");
context.Identity.AddClaim(accessTokenClaim);
var extraClaims = GetAdditionalFacebookClaims(accessTokenClaim);
context.Identity.AddClaim(new Claim(ClaimTypes.Email, extraClaims.First(k => k.Key == "email").Value.ToString()));
context.Identity.AddClaim(new Claim("Provider", context.Identity.AuthenticationType));
context.Identity.AddClaim(new Claim(ClaimTypes.Name, context.Identity.FindFirstValue(ClaimTypes.Name)));
var userDetail = context.User;
var link = userDetail.Value<string>("link") ?? string.Empty;
context.Identity.AddClaim(new Claim("link", link));
context.Identity.AddClaim(new Claim("FacebookId", userDetail.Value<string>("id")));
return System.Threading.Tasks.Task.FromResult(0);
}
private static JsonObject GetAdditionalFacebookClaims(Claim accessToken)
{
var fb = new FacebookClient(accessToken.Value);
return fb.Get("me", new { fields = new[] { "email", "first_name", "last_name" } }) as JsonObject;
}
}
My Startup.cs has this within Configuration(IAppBuilder app):
FacebookAuthOptions = new Microsoft.Owin.Security.Facebook.FacebookAuthenticationOptions
{
AppId = "YOUR APP ID",
AppSecret = "YOUR APP SECRET",
Microsoft.Owin.PathString("/Account/ExternalCallBack"), // whatever your external callback url is
Provider = new FacebookAuthProvider()
};
FacebookAuthOptions.Scope.Add("email");
app.UseFacebookAuthentication(FacebookAuthOptions);
I've no idea why the email was not being populated in the first place, but this approach worked for me.
I am using Identity Server 3 with Entity Framework. My ASP.NET MVC app logs in to the SSO/IdentityServer app using below configuration and then that access token is saved in a cookie which is used by javascript to call our API.
Problem is when I login to my ASP.NET MVC app then I go to database and delete that token from the database table, then my API says invalid bearer token as expected, but when I the refresh page in the ASP.NET MVC app, it still shows as logged in and I think it's because of cookie configuration.
How can I ask MVC app to always validate token from server?
AuthConfig.cs of ASP.NET MVC application:
public static class AuthConfig
{
public static void RegisterAuth(IAppBuilder app)
{
ServicePointManager.ServerCertificateValidationCallback =
(sender, certificate, chain, sslPolicyErrors) => true;
JwtSecurityTokenHandler.InboundClaimTypeMap = new Dictionary<string, string>();
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = "Cookies",
SlidingExpiration = true,
ExpireTimeSpan = SellutionConstants.Globals.AccessTokenExpirationTimeSpan
});
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
ClientId = "sellutionapp",
Authority = SsoConfigHelper.SellutionSts,
ResponseType = "code id_token",
Scope = "openid profile roles all_claims " + SsoConfigHelper.SellutionApiScope,
UseTokenLifetime = false,
TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = "name",
RoleClaimType = "role",
},
SignInAsAuthenticationType = "Cookies",
Notifications = new OpenIdConnectAuthenticationNotifications
{
AuthorizationCodeReceived = async n =>
{
// use the code to get the access and refresh token
var tokenClient = new TokenClient(
SsoConfigHelper.SellutionStsTokenEndpoint,
"sellutionapp",
"secret");
if (String.IsNullOrEmpty(n.RedirectUri))
{
n.RedirectUri = n.Request.Scheme + "://" + n.Request.Host + n.Request.PathBase;
}
var tokenResponse = await tokenClient.RequestAuthorizationCodeAsync(n.Code, n.RedirectUri);
if (tokenResponse.IsError)
{
throw new Exception(tokenResponse.Error);
}
// use the access token to retrieve claims from userinfo
var userInfoClient = new UserInfoClient(
new Uri(SsoConfigHelper.SellutionStsUserInfoEndpoint),
tokenResponse.AccessToken);
var userInfoResponse = await userInfoClient.GetAsync();
// create new identity
var id = new ClaimsIdentity(n.AuthenticationTicket.Identity.AuthenticationType);
id.AddClaims(userInfoResponse.GetClaimsIdentity().Claims);
id.AddClaim(new Claim("access_token", tokenResponse.AccessToken));
id.AddClaim(new Claim("expires_at", DateTime.Now.AddSeconds(tokenResponse.ExpiresIn).ToLocalTime().ToString()));
//id.AddClaim(new Claim("refresh_token", tokenResponse.RefreshToken));
id.AddClaim(new Claim("id_token", n.ProtocolMessage.IdToken));
id.AddClaim(new Claim("sid", n.AuthenticationTicket.Identity.FindFirst("sid").Value));
LoginCookieHelper.SetUserData(tokenResponse.AccessToken);
n.AuthenticationTicket = new AuthenticationTicket(
new ClaimsIdentity(id.Claims, n.AuthenticationTicket.Identity.AuthenticationType, "name", "role"),
n.AuthenticationTicket.Properties);
},
RedirectToIdentityProvider = n =>
{
// This ensures that the address used for sign in and sign out is picked up dynamically from the request
// this allows you to deploy the app (to Azure Web Sites, for example) without having to change settings.
var appBaseUrl = n.Request.Scheme + "://" + n.Request.Host + n.Request.PathBase;
n.ProtocolMessage.RedirectUri = appBaseUrl;
n.ProtocolMessage.PostLogoutRedirectUri = appBaseUrl;
// if signing out, add the id_token_hint
if (n.ProtocolMessage.RequestType == OpenIdConnectRequestType.LogoutRequest)
{
var idTokenHint = n.OwinContext.Authentication.User.FindFirst("id_token");
if (idTokenHint != null)
{
n.ProtocolMessage.IdTokenHint = idTokenHint.Value;
}
}
return Task.FromResult(0);
}
}
});
}
}
Identity server configuration:
class Factory
{
public static IdentityServerServiceFactory Configure()
{
var efConfig = new EntityFrameworkServiceOptions
{
ConnectionString = "DefaultConnection",
};
// these two calls just pre-populate the test DB from the in-memory config
ConfigureClients(Clients.Get(), efConfig);
ConfigureScopes(Scopes.Get(), efConfig);
var factory = new IdentityServerServiceFactory();
//var scopeStore = new InMemoryScopeStore(Scopes.Get());
//factory.ScopeStore = new Registration<IScopeStore>(scopeStore);
//var clientStore = new InMemoryClientStore(Clients.Get());
//factory.ClientStore = new Registration<IClientStore>(clientStore);
factory.CorsPolicyService = new Registration<ICorsPolicyService>(new DefaultCorsPolicyService { AllowAll = true });
factory.RegisterOperationalServices(efConfig);
factory.RegisterConfigurationServices(efConfig);
return factory;
}
public static void ConfigureClients(IEnumerable<Client> clients, EntityFrameworkServiceOptions options)
{
using (var db = new ClientConfigurationDbContext(options.ConnectionString, options.Schema))
{
if (!db.Clients.Any())
{
foreach (var c in clients)
{
var e = c.ToEntity();
db.Clients.Add(e);
}
db.SaveChanges();
}
}
}
public static void ConfigureScopes(IEnumerable<Scope> scopes, EntityFrameworkServiceOptions options)
{
using (var db = new ScopeConfigurationDbContext(options.ConnectionString, options.Schema))
{
if (!db.Scopes.Any())
{
foreach (var s in scopes)
{
var e = s.ToEntity();
db.Scopes.Add(e);
}
db.SaveChanges();
}
}
}
}
IdentityServer client configuration
public class Clients
{
public static List<Client> Get()
{
return new List<Client>
{
new Client
{
ClientName = "Resource Owner Flow",
ClientId = "resourceowner",
ClientSecrets = new List<Secret> {new Secret("vkgk8M4pj".Sha256())},
Flow = Flows.ResourceOwner , //Password authentication
PrefixClientClaims = false,
AccessTokenType = AccessTokenType.Jwt,
AllowedScopes = new List<string>
{
Constants.StandardScopes.OpenId,
Constants.StandardScopes.Profile,
Constants.StandardScopes.Email,
Constants.StandardScopes.Roles,
Constants.StandardScopes.Address,
Constants.StandardScopes.AllClaims,
Constants.StandardScopes.OfflineAccess,
SsoConfigHelper.SellutionApiScope
},
RequireConsent = false,
AllowRememberConsent = true,
LogoutSessionRequired = true,
RefreshTokenExpiration = TokenExpiration.Absolute,
RefreshTokenUsage = TokenUsage.OneTimeOnly,
UpdateAccessTokenClaimsOnRefresh = true,
AbsoluteRefreshTokenLifetime =(int)TimeSpan.FromDays(1).TotalSeconds
},
/////////////////////////////////////////////////////////////
// MVC OWIN Implicit Client
/////////////////////////////////////////////////////////////
new Client
{
ClientName = "Sellution Application",
ClientId = "sellutionapp",
Flow = Flows.Hybrid,
AllowAccessTokensViaBrowser = false,
AllowedScopes = new List<string>
{
Constants.StandardScopes.OpenId,
Constants.StandardScopes.Profile,
Constants.StandardScopes.Email,
Constants.StandardScopes.Roles,
Constants.StandardScopes.Address,
Constants.StandardScopes.AllClaims,
SsoConfigHelper.SellutionApiScope
},
ClientSecrets = new List<Secret>
{
new Secret("secret".Sha256())
},
AccessTokenType = AccessTokenType.Reference,
RequireConsent = false,
AllowRememberConsent = true,
LogoutSessionRequired = true,
},
};
}
}
You need to sign the user out of the MVC application as well because according to your code you are using Cookie Authentication named Cookies you also have to do a sign out on that authentication scheme when they log out (not deleteing the token in the store).
AuthenticationManager.SignOut("Cookies"); is what your controller action will require for logout.
I have seen many posts for facebook authentication , either those are old or not working correctly as it should be.
However finally I have made something in my project that works but not fully. Here is code where I ask for
var facebookAuthenticationOptions = new FacebookAuthenticationOptions()
{
AppId = "...ID",
AppSecret = "...AppSecret",
AuthenticationType = "Facebook",
SignInAsAuthenticationType = "ExternalCookie",
//Provider = new FacebookAuthenticationProvider
//{
// OnAuthenticated = async ctx =>
// {
// if (ctx.User["birthday"] != null)
// {
// ctx.Identity.AddClaim(new Claim(ClaimTypes.DateOfBirth,ctx.User["birthday"].ToString()));
// }
// }
//}
};
facebookAuthenticationOptions.Scope.Add("user_birthday");
//facebookAuthenticationOptions.Scope.Add("first_name");
//facebookAuthenticationOptions.Scope.Add("last_name");
//page goes blank if ask for first_name,last_name , if comment out works
//but doesn give date of birth or likes or other things.
facebookAuthenticationOptions.Scope.Add("publish_stream");
facebookAuthenticationOptions.Scope.Add("user_likes");
facebookAuthenticationOptions.Scope.Add("friends_likes");
facebookAuthenticationOptions.Scope.Add("read_stream");
facebookAuthenticationOptions.Scope.Add("email");
app.UseFacebookAuthentication(facebookAuthenticationOptions);
Can anyone please help me why I am not getting friends_like,birthday, user_likes and so on.
In addition, how to get those string values(ie. "user_birthday","first_name") for information retrieval, like how would I know that "user_birthday" returns date of birthday(I got it from searching) , is there any list which have this string names(ie. "user_birthday","first_name") ?
If I use google authentication is it possible to get phone number or first name,last name?
Solved it,
References there : https://developers.facebook.com/docs/facebook-login/permissions/v2.1#reference
var facebookAuthenticationOptions = new FacebookAuthenticationOptions() {
AppId = ".....",
AppSecret = ".....",
AuthenticationType = "Facebook",
SignInAsAuthenticationType = "ExternalCookie",
Provider = new FacebookAuthenticationProvider {
OnAuthenticated = async ctx => {
ctx.Identity.AddClaim(new Claim(ClaimTypes.DateOfBirth, ctx.User["birthday"].ToString()));
ctx.Identity.AddClaim(new Claim(ClaimTypes.Country, ctx.User["birthday"].ToString()));
ctx.Identity.AddClaim(new Claim(ClaimTypes.Gender, ctx.User["birthday"].ToString()));
ctx.Identity.AddClaim(new Claim(ClaimTypes.MobilePhone, ctx.User["birthday"].ToString()));
ctx.Identity.AddClaim(new Claim(ClaimTypes.OtherPhone, ctx.User["birthday"].ToString()));
ctx.Identity.AddClaim(new Claim(ClaimTypes.HomePhone, ctx.User["birthday"].ToString()));
ctx.Identity.AddClaim(new Claim(ClaimTypes.StateOrProvince, ctx.User["birthday"].ToString()));
ctx.Identity.AddClaim(new Claim(ClaimTypes.Email, ctx.User["birthday"].ToString()));
ctx.Identity.AddClaim(new Claim(ClaimTypes.Country, ctx.User["birthday"].ToString()));
ctx.Identity.AddClaim(new Claim(ClaimTypes.Actor, ctx.User["birthday"].ToString()));
ctx.Identity.AddClaim(new Claim(ClaimTypes.DateOfBirth, ctx.User["birthday"].ToString()));
}
}
};
facebookAuthenticationOptions.Scope.Add("user_birthday");
//facebookAuthenticationOptions.Scope.Add("first_name");
//facebookAuthenticationOptions.Scope.Add("last_name");
facebookAuthenticationOptions.Scope.Add("publish_stream");
facebookAuthenticationOptions.Scope.Add("user_likes");
facebookAuthenticationOptions.Scope.Add("friends_likes");
facebookAuthenticationOptions.Scope.Add("user_about_me");
facebookAuthenticationOptions.Scope.Add("user_friends");
facebookAuthenticationOptions.Scope.Add("user_actions.news");
facebookAuthenticationOptions.Scope.Add("user_actions.video");
facebookAuthenticationOptions.Scope.Add("user_education_history");
facebookAuthenticationOptions.Scope.Add("manage_pages");
facebookAuthenticationOptions.Scope.Add("user_interests");
facebookAuthenticationOptions.Scope.Add("user_location");
facebookAuthenticationOptions.Scope.Add("user_photos");
facebookAuthenticationOptions.Scope.Add("user_relationships");
facebookAuthenticationOptions.Scope.Add("user_relationship_details");
facebookAuthenticationOptions.Scope.Add("user_status");
facebookAuthenticationOptions.Scope.Add("user_tagged_places");
facebookAuthenticationOptions.Scope.Add("user_videos");
facebookAuthenticationOptions.Scope.Add("user_website");
facebookAuthenticationOptions.Scope.Add("read_friendlists");
facebookAuthenticationOptions.Scope.Add("read_stream");
facebookAuthenticationOptions.Scope.Add("email");
app.UseFacebookAuthentication(facebookAuthenticationOptions);
ctx got all the information.. Just have to go through it.
Still don't have information on how to get google first,last name and phone number + date of birth.
Or how to access user contacts from gmail account.
You can just loop through context.User to get all claims
var facebookAuthOptions = new FacebookAuthenticationOptions();
facebookAuthOptions.AppId = "..."; //Enter your AppId
facebookAuthOptions.AppSecret = "..."; //Enter your AppSecret
facebookAuthOptions.Provider = new FacebookAuthenticationProvider()
{
OnAuthenticated = async context =>
{
context.Identity.AddClaim(new System.Security.Claims.Claim("FacebookAccessToken", context.AccessToken));
foreach (var claim in context.User)
{
var claimType = string.Format("urn:facebook:{0}", claim.Key);
string claimValue = claim.Value.ToString();
if (!context.Identity.HasClaim(claimType, claimValue))
context.Identity.AddClaim(new System.Security.Claims.Claim(claimType, claimValue, "XmlSchemaString", "Facebook"));
}
}
};
The same goes for Google
var googleAuthOptions = new GoogleOAuth2AuthenticationOptions();
googleAuthOptions.ClientId = "..."; //Enter your ClientId
googleAuthOptions.ClientSecret = "..."; //Enter your ClientSecret
googleAuthOptions.Provider = new GoogleOAuth2AuthenticationProvider()
{
OnAuthenticated = async context =>
{
context.Identity.AddClaim(new System.Security.Claims.Claim("GoogleAccessToken", context.AccessToken));
foreach (var claim in context.User)
{
var claimType = string.Format("urn:google:{0}", claim.Key);
string claimValue = claim.Value.ToString();
if (!context.Identity.HasClaim(claimType, claimValue))
context.Identity.AddClaim(new System.Security.Claims.Claim(claimType, claimValue, "XmlSchemaString", "Google"));
}
}
};
And I think User's privacy settings and your application permissions control which claims you can get.