I am using Facebook SDK to get email of user. I write this code in Startup.Auth.css class :
var x = new FacebookAuthenticationOptions();
x.Scope.Add("email");
x.AppId = "421656951358309";
x.AppSecret = "5a2e5ccf163fe6918b6d6fdc8dda5184";
x.Provider = new FacebookAuthenticationProvider()
{
OnAuthenticated = async context =>
{
context.Identity.AddClaim(new System.Security.Claims.Claim("FacebookAccessToken", context.AccessToken));
}
};
x.SignInAsAuthenticationType = DefaultAuthenticationTypes.ExternalCookie;
app.UseFacebookAuthentication(x);
And in controller, I use two method to get email but both methods fail. Here is the methods :
Method 1 : By default, after executing the first line the variable info has email property. But it always return null.
var info = await AuthenticationManager.GetExternalLoginInfoAsync();
string email = info.Email;
Method 2 : I use the following code, it also return null.
var fb = new FacebookClient(access_token.Value);
dynamic me = fb.Get("email");
string email = me.email;
Did I miss something ? or there is another method that I can use. I can get others information such as username, but for email I can't.
try to modify Method 2 as follow :
var fb = new FacebookClient(access_token.Value);
dynamic me = fb.Get("/me?fields=email");
string email = me.email;
Method 2 should be work with facebook app before version 2.4, but for version 2.4 and I guess it is the version of your app you should edit :
dynamic me = fb.Get("/me?fields=email");
Related
I need to implement SSO in a .net framework web application environment. Need to authenticate and retrieve the samaccountname of the logged user.
I have a working code, but only works on a Desktop and mobile device environments, I guess because I’m using "PublicClientApplicationBuilder".
Sample working code for desktop:
string clientId = "c8a73432-9383-4e7c.....";
string tenantId = "efe4a126-2f4f-42ef.....";
var app = PublicClientApplicationBuilder.Create(clientId)
.WithTenantId(tenantId)
.WithRedirectUri(http://localhost)
.Build();
string[] scopes = new string[]
{
https://graph.microsoft.com/User.Read
};
var result = await app.AcquireTokenInteractive(scopes)
.ExecuteAsync();
var stream = result.IdToken.ToString(); // return IDtoken with samaccountname
Does anybody have a sample code working for a web app?
I have tried with "ConfidentialClientApplicationBuilder", but doesn’t work:
string clientId = "c8a73432-9383...";
string tenantId = "efe4a126-2f4f...";
string secret = "1qN8Q~4m7qD5_...";
string authorityUri = $https://login.microsoftonline.com/efe4e126-2f4f-42ef...;
var app = ConfidentialClientApplicationBuilder.Create(clientId)
.WithClientSecret(secret)
.WithAuthority(new Uri(authorityUri))
.WithRedirectUri(http://localhost)
.Build();
string[] scopes = new string[]
{
https://graph.microsoft.com/User.Read
};
var accessTokenRequest = app.AcquireTokenForClient(scopes);
var accessToken = accessTokenRequest.ExecuteAsync().Result.AccessToken;
Thx in advance!
List item
In a confidential client application, you usually have a cache per user. Therefore you will need to get the cache associated with the user and inform the application builder that you want to use it. In the same way, you might have a dynamically computed redirect URI.
could you please add below code ,
TokenCache userTokenCache = _tokenCacheProvider.SerializeCache(app.UserTokenCache,httpContext, claimsPrincipal);
please refer doc- Retrieve logged user info from microsoft graph in a framework .net environment .
if still it doesn't work, as you said it doesn't work , we would like to know what error you got?
I am using a web api 2 and creating a message object to save to the database. This message object needs to have the current user stored on it as an application user type.
My code looks like this:
var UserManager = Request.GetOwinContext().GetUserManager<ApplicationUserManager>();
var currentUser = RequestContext.Principal;
var currentUserName = currentUser.Identity.Name;
var currentApplicationUser = UserManager.FindByName(currentUserName);
// I perhaps want to dispose of the user context?
// UserManager.Dispose();
globalMessage.sentBy = currentApplicationUser;
db.GlobalMessages.Add(globalMessage);
The last line is throwing the error: An entity object cannot be referenced by multiple instances of IEntityChangeTracker.
Is there another way around this. Otherwise, I imagine, I could call an action which gets the current user, redirect to another action from the action with this user as an arg and then perform the update?
I worked it out:
var currentUser = RequestContext.Principal;
var currentUserName = currentUser.Identity.Name;
var sender = db.Users.Where(u => u.UserName == currentUserName).FirstOrDefault();
globalMessage.sentBy = sender;
db.GlobalMessages.Add(globalMessage);
db.SaveChanges();
The problem is you're attaching to your db context an entity (currentApplicationUser) that already is attached to another context instance that is alive too, so a solution could be to find the user using the same context, in your case it would be something like:
var UserManager = Request.GetOwinContext().GetUserManager<ApplicationUserManager>();
var currentUser = RequestContext.Principal;
var currentUserName = currentUser.Identity.Name;
var currentApplicationUser =db.AspNetUsers.FirstOrDefault(u=>u.UserName==currentUserName);
globalMessage.sentBy = currentApplicationUser;
db.GlobalMessages.Add(globalMessage);
I am using the sample code from the crm samples that come with the sdk and this error keeps showing. How to i add this serverconnection missing reference? I am at a loss to find where it is to add it? or what namespace it belongs to?
This is a connection code for crm online I hope you serve:
ClientCredentials Credentials = new ClientCredentials();
Credentials.UserName.UserName = UserName;
Credentials.UserName.Password = Password;
Credentials.Windows.ClientCredential = CredentialCache.DefaultNetworkCredentials;
Uri OrganizationUri = new Uri(Crmserverurl);
Uri HomeRealmUri = null;
using (OrganizationServiceProxy serviceProxy = new OrganizationServiceProxy(OrganizationUri, HomeRealmUri, Credentials, null))
{
crmSvc = (IOrganizationService)serviceProxy;
}
We are using Microsoft's Identity Framework v2.0 in a web forms application. All is working well. We decided we want to add email verification as part of the new account set up process. If we validate the token after it is created in the same page, we are successful. But if we try to validate the token in a different page, it fails. The process is very simple:
Admin creates a new account by providing user's email and name. (we do not support self registration).
User clicks link he gets in email to validate the email was received.
Here is the code to create the email verification token:
var manager = new UserManager();
var user = new ApplicationUser() { UserName = EmailAddress.Text, Email = EmailAddress.Text, FirstName = FirstName.Text, LastName = LastName.Text };
IdentityResult result = manager.Create(user);
var provider = new DpapiDataProtectionProvider();
manager.UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser>(provider.Create("EmailConfirmation"))
{
TokenLifespan = TimeSpan.FromHours(24)
};
var strToken = manager.GenerateEmailConfirmationToken(user.Id);
//IdentityResult validToken = manager.ConfirmEmail(user.Id, strToken);
strToken = HttpUtility.UrlEncode(strToken.ToString());
NOTE: If we uncomment the line beginning //IdentityResult validToken..., then it succeeds.
Here is the code on the VerifyEmail page:
string userid = Request.QueryString["id"].ToString();
string tokenReceived = Request.QueryString["token"].ToString();
//tokenReceived = HttpUtility.UrlDecode(tokenReceived);
ApplicationUser User = new ApplicationUser();
var manager = new UserManager();
User = manager.FindById(userid);
var provider = new DpapiDataProtectionProvider();
manager.UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser>(provider.Create("EmailConfirmation"))
{
TokenLifespan = TimeSpan.FromHours(24)
};
IdentityResult validToken = manager.ConfirmEmail(User.Id, tokenReceived);
The validToken line does not succeed in this file. I have validated that the strings User.Id and tokenReceived match EXACTLY in both file, so there is no URL corruption going on. (That is why I commented out the UrlDecode since it seems to be decoded by the browser automatically - when I try to decode, it is not 100% the same as the string before encoding).
So I am certain we are calling the same method (ConfirmEmail) and that the two parameters that are passed are exactly the same strings. I am also aware that a token can only be validated once, so I am not trying to re-use them after once validating them.
Any ideas would be welcome.
I think the problem in DpapiDataProtectionProvider - If you use the same instance of this class in creating and validating the token, it'll work fine.
Any reason you are not getting UserManager from Owin Context as per VC2013 template?
I have searched online on the following code for getting code information, but I have some questions
1) facebook.Options.Scope.Add("email") : How to determine what to put in email? For example what should I put if I need name or first name?
2) ext.Claims.First(x => x.Type.Contains("email")).Value;
How do I determine the email here? Let's say I want first name, how do I know the first name is first_name of first-name of firstname
var facebookOptions = new Microsoft.Owin.Security.Facebook.FacebookAuthenticationOptions()
{
AppId = "AppId",
AppSecret = "AppSecret"
};
facebookOptions.Scope.Add("email");
app.UseFacebookAuthentication(facebookOptions);
ClaimsIdentity ext = await AuthenticationManager.GetExternalIdentityAsync(DefaultAuthenticationTypes.ExternalCookie);
var email = ext.Claims.First(x => x.Type.Contains("email")).Value;
You can't directly get all of Facebook profile information from claims added through facebookOptions scope. You have to add scopes like below and use FacebookClient as explain.
var facebookOptions = new Microsoft.Owin.Security.Facebook.FacebookAuthenticationOptions()
{
AppId = "AppId",
AppSecret = "AppSecret"
};
facebookOptions.Scope.Add("email");
facebookOptions.Scope.Add("public_profile");
app.UseFacebookAuthentication(facebookOptions);
Then you can get Facebook user information using FacebookClient.
[Authorize]
public async Task<ActionResult> FacebookInfo()
{
var claimsforUser = await UserManager.GetClaimsAsync(User.Identity.GetUserId());
var access_token = claimsforUser.FirstOrDefault(x => x.Type == "FacebookAccessToken").Value;
var fb = new FacebookClient(access_token);
dynamic myInfo = fb.Get("/me"); **// Check this with Facebook api to get profile information.**
}
Note that: If you only need to get Facebook user full name, then check your claims, you'll see user's full name is there.
More information
Hope this helps,