Microsoft Bot Framework - Facebook authentication, account linking - c#

I want to authorize user through bot and get proper information from database while chatting.
User is registered to my website database using facebook account.
So far, I have this:
var resultMessage = context.MakeMessage();
resultMessage.Type = "message";
resultMessage.Attachments = new List<Attachment>();
List<CardAction> cardButtons = new List<CardAction>();
List<CardAction> plButton = new List<CardAction>();
plButton.Add(new CardAction
{
Value = "myurl/link",
Type = "signin",
Title = "LogIn"
});
SigninCard plCard = new SigninCard("You need to authorize me", plButton);
Attachment plAttachment = plCard.ToAttachment();
resultMessage.Attachments.Add(plAttachment);
On the other side, where I should authorize the user, I have this:
public Uri link(string resource, string clientId, Uri redirectUri, User userId, string extraQueryParameters)
{
return redirectUri;
}
But that's not correct.
What parameters should I send?
How to handle this?
How to redirect user on Facebook Messenger, again?
How to authenticate and get (stored) userdata from my database into bot ?
Thank you in advance for your replies!

Related

Error - "The requested user is invalid" while sendmail using graph api

I am trying to send mail on behalf of some users using the Microsoft Graph API through my Winforms application. I registered the app in Application Registration at Azure Portal in my tenant and assigned application permissions for sending mail to the app. I am using client credentials flow for sending mail.
The mail is successfully sent when sending the mail on behalf of my tenant user. Then I granted the admin consent to my app from another tenant and tried to send mail on behalf of that tenant's user but I get an error
Code: ErrorInvalidUser
Message: The requested user 'foo#tenanttwo.onmicrosoft.com' is invalid.
That user has a valid license of O365.
Can we send the mail on behalf of other tenant's user using the Microsoft Graph API? If yes then please help me what else I need to do?
This is the code I'm using:
var scopes = new[] { "https://graph.microsoft.com/.default" };
// using Azure.Identity;
var options = new TokenCredentialOptions
{
AuthorityHost = AzureAuthorityHosts.AzurePublicCloud
};
// https://learn.microsoft.com/dotnet/api/azure.identity.clientsecretcredential
var clientSecretCredential = new ClientSecretCredential(tenantID, clientId, clientSecret, options);
var graphClient = new GraphServiceClient(clientSecretCredential, scopes);
var message = new Microsoft.Graph.Message
{
Subject = strSubject,
Body = new ItemBody
{
ContentType = BodyType.Text,
Content = strBody
},
ToRecipients = new List<Recipient>()
{
new Recipient
{
EmailAddress = new EmailAddress
{
Address = strTo
}
}
}
};
var saveToSentItems = true;
await graphClient.Users[senderMail]
.SendMail(message, saveToSentItems)
.Request()
.PostAsync();

How can I get full facebook profile from ASP.NET MVC

I am developing web app, where I need to get full information about facebook user. OAUTH2 login is done successfully. But after that when I call graph.facebook.api using provided access token I get only id, name and picture.
The question is how can I get full user profile from facebook?
In Startup.Auth.cs I have following code:
var facebookAuthOptions = new FacebookAuthenticationOptions()
{
AppId = "APP_ID_HERE",
AppSecret = "APP_SECRET_HERE",
Provider = new FacebookAuthenticationProvider()
{
OnAuthenticated = (context) =>
{
context.Identity.AddClaim(new System.Security.Claims.Claim("urn:facebook:accesstoken"
, context.AccessToken
, ClaimValueTypes.String
, "Facebook"));
context.Identity.AddClaim(new Claim("urn:facebook:email"
, context.AccessToken
, ClaimValueTypes.Email
, "Facebook"));
context.Identity.AddClaim(new Claim("urn:facebook:about"
, context.AccessToken
, ClaimValueTypes.String
, "Facebook"));
return Task.FromResult(0);
}
}
};
app.UseFacebookAuthentication(facebookAuthOptions);
And in my controller I am calling facebook API like this:
var apiRequestUri = new Uri("https://graph.facebook.com/v2.8/me?fields=email,name,about,picture&access_token=" + accessToken);
var webClient = new System.Net.WebClient();
var json = webClient.DownloadString(apiRequestUri);
var profile = JsonConvert.DeserializeObject<FacebookProfile>(json);
But what I get is only id, name and picture.
When I try similar query in graph api console, I can get all of the information required.
Any suggestions are welcome!
Thank you in advance for your help!
I have resolved this by adding claims to the facebookAuthOptions for each of the field required. After user approves requested info, then I can successfully get response from Facebook API using token provided on authorization step.

Request additional claims Owin Security

I am trying to retrieve additional information from a google OAuth handshake using OWIN Security.
I have the following to request the user profile claim from Google and the google permissions page reflects that this claim is requested.
var googleConfig = new Microsoft.Owin.Security.Google.GoogleOAuth2AuthenticationOptions
{
ClientId = ClientId",
ClientSecret = "Secret"
};
googleConfig.Scope.Add("https://www.googleapis.com/auth/userinfo.profile");
app.UseGoogleAuthentication(googleConfig);
However when i get the response back using AuthenticationManager.GetExternalLoginInfoAsync(); there is only one name claim on the user.
What do i need to do to get back the user profile data from google on login?
You need to access the additional claims in the Provider's OnAuthenticate event. In there the context param contains these additional properties you asked for in the scopes. For exmaple, when using Facebook:
var fb = new FacebookAuthenticationOptions
{
AppId = "...",
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()));
}
}
}
};
fb.Scope.Add("user_birthday");
app.UseFacebookAuthentication(fb);

Facebook OAuth issue MVC4

Annoyingly I have been trying to solve this issue for many hours, every answer is no direct solution:
{
"error": {
"message": "Error validating verification code. Please make sure your redirect_uri is identical to the one you used in the OAuth dialog request",
"type": "OAuthException",
"code": 100
}
}
I have been banging my head against the wall!. I am using the facebook soap client for this http://pastebin.com/G7ysgbdX
This will allow us to integrate (with the user's permission) their timeline. Facebook is saying the URL's do not match. How do I test this?
This works locally but not on the server with the exact same code except http://free-rsvp.com/ instead of localhost:53111/
This is the below URL. I cannot see anything wrong!
Any advice would be appreciated.
provider_%3dFacebookPro%26_sid_%3da80359b555c54b8f8d2f4f8e803f9125&client_secret=212360b3ea6478fd0a0491e736b54256&code=AQCyTDStiB5gsQpKMx4uI1yFesVnLnWfE3u70VsB02-4HSyUCTbcf_3oHMo7QQI2as_pw1tpFONs8tClq4FxCr4AzuCMzLBsRnyOM3dcattTATdU-ahq5cjr4lPJNp2gkTrpgWUmqDEVQ8PBvYFB1LdWJpojxRIC24lv0GkQSSqdrct41UGHfDjhnPfI1mV945NgVJSfebhJP7O0GWxP9o9g_4svDCKa2LtCRbo7nDfWLeiE9fGULhmuJDjefAFZ5VMiYj8SrA4QtZXIu8jUQSQT89VYEP8PuG2hS_wMr0TL_GmcvEhNzQ8psPpPWFYhmSo">https://graph.facebook.com/oauth/access_token?client_id=523007704381837&redirect_uri=http%3a%2f%2ffree-rsvp.com%3a80%2fAccount%2fExternalLoginCallback%3fReturnUrl%3d%252FDashboard%26_provider_%3dFacebookPro%26_sid_%3da80359b555c54b8f8d2f4f8e803f9125&client_secret=212360b3ea6478fd0a0491e736b54256&code=AQCyTDStiB5gsQpKMx4uI1yFesVnLnWfE3u70VsB02-4HSyUCTbcf_3oHMo7QQI2as_pw1tpFONs8tClq4FxCr4AzuCMzLBsRnyOM3dcattTATdU-ahq5cjr4lPJNp2gkTrpgWUmqDEVQ8PBvYFB1LdWJpojxRIC24lv0GkQSSqdrct41UGHfDjhnPfI1mV945NgVJSfebhJP7O0GWxP9o9g_4svDCKa2LtCRbo7nDfWLeiE9fGULhmuJDjefAFZ5VMiYj8SrA4QtZXIu8jUQSQT89VYEP8PuG2hS_wMr0TL_GmcvEhNzQ8psPpPWFYhmSo
EDIT
The url that takes me to facebook is:
provider_%253DFacebookPro%2526_sid_%253Dbfe82f104ab34d1aa0f44c477c4d7819%26scope%3Demail%252Cuser_likes%252Cfriends_likes%252Cuser_birthday%252Cpublish_checkins%252Cpublish_stream%26client_id%3D523007704381837%26ret%3Dlogin&cancel_uri=http%3A%2F%2Ffree-rsvp.com%2FAccount%2FExternalLoginCallback%3FReturnUrl%3D%252FDashboard%26_provider_%3DFacebookPro%26_sid_%3Dbfe82f104ab34d1aa0f44c477c4d7819%26error%3Daccess_denied%26error_code%3D200%26error_description%3DPermissions%2Berror%26error_reason%3Duser_denied%23_%3D_&display=page">https://www.facebook.com/login.php?skip_api_login=1&api_key=523007704381837&signed_next=1&next=https%3A%2F%2Fwww.facebook.com%2Fdialog%2Foauth%3Fredirect_uri%3Dhttp%253A%252F%252Ffree-rsvp.com%252FAccount%252FExternalLoginCallback%253FReturnUrl%253D%252FDashboard%2526_provider_%253DFacebookPro%2526_sid_%253Dbfe82f104ab34d1aa0f44c477c4d7819%26scope%3Demail%252Cuser_likes%252Cfriends_likes%252Cuser_birthday%252Cpublish_checkins%252Cpublish_stream%26client_id%3D523007704381837%26ret%3Dlogin&cancel_uri=http%3A%2F%2Ffree-rsvp.com%2FAccount%2FExternalLoginCallback%3FReturnUrl%3D%252FDashboard%26_provider_%3DFacebookPro%26_sid_%3Dbfe82f104ab34d1aa0f44c477c4d7819%26error%3Daccess_denied%26error_code%3D200%26error_description%3DPermissions%2Berror%26error_reason%3Duser_denied%23_%3D_&display=page
here is a piece of my server-side authentication code (MVC4 project). The part you should look at is how redirect URL is generated - identically - in both "Authorize" and "AuthorizeCallback" functions - and passed to facebook client:
[HttpPost]
public ActionResult Authorize(Guid eventId)
{
var #event = this.eventRepository.Find(eventId);
var redirectUri = ConfigurationProvider.HostingEndpoint + this.Url.Action("AuthorizeCallback", new { eventCode = #event.Code });
var service = new FacebookClient();
var loginUrl = service.GetLoginUrl(new {
client_id = ConfigurationProvider.FacebookAppId,
client_secret = ConfigurationProvider.FacebookAppSecret,
redirect_uri = redirectUri,
response_type = "code",
scope = "manage_pages, publish_actions, user_photos, publish_stream" // Add other permissions as needed
});
return new RedirectResult(loginUrl.AbsoluteUri, permanent: false);
}
public ActionResult AuthorizeCallback(string code, string eventCode, UserProfile userProfile)
{
var #event = this.eventRepository.Find(eventCode);
if (string.IsNullOrWhiteSpace(code) == true)
{
// means user clicked "cancel" when he was prompted to authorize the app
// todo: show some error message? or just redirect back?
return this.RedirectToAction("Event", "Dashboard", new { eventCode = #event.Code, feature = FeatureType.Update });
}
var redirectUri = ConfigurationProvider.HostingEndpoint + this.Url.Action("AuthorizeCallback", new { eventCode = #event.Code });
var fb = new FacebookClient();
dynamic result = fb.Post("oauth/access_token", new
{
client_id = ConfigurationProvider.FacebookAppId,
client_secret = ConfigurationProvider.FacebookAppSecret,
redirect_uri = redirectUri,
code = code
});
var accessToken = result.access_token;
// update the facebook client with the access token so
// we can make requests on behalf of the user
fb.AccessToken = accessToken;
// Get the user's information
dynamic me = fb.Get("me");
return this.RedirectToAction("Event", "Dashboard", new { eventCode = #event.Code, feature = FeatureType.Update });
}

Facebook C# SDK Post to Page as Page

I have been struggling to get the Facebook C# SDK to post to my page, as the page for a couple of days.
From my googling, I have found that the process should be as follows:
Authorize application for manage_pages and publish_stream with my user account (done through this URL: https://graph.facebook.com/oauth/authorize?client_id=CLIENT_ID&redirect_uri=REDIRECT_URI&scope=publish_stream,manage_pages)
Get user access token
Exchange user access token for long lived access token
Get me/accounts with the long lived user access token
Get the page access token from the result
Post to the page_id/feeds endpoint using the long lived token
I can follow this process through the graph explorer, and it works. A post is created on the page with the generated token.
How do I do this using the C# SDK?
I tried:
dynamic userTokenResult = client.Get("oauth/access_token", new
{
client_id = appid,
client_secret = appsecret,
grant_type = "client_credentials"
});
dynamic longLivedResult = client.Get("oauth/access_token", new
{
client_id = appid,
client_secret = appsecret,
grant_type = "fb_exchange_token",
fb_exchange_token = userTokenResult.access_token;
});
client.AccessToken = longLivedResult.access_token;
// Post the message
dynamic messagePost = new
{
link = message.LinkUrl,
name = message.LinkName,
caption = message.LinkCaption,
description = message.LinkDescription,
message = message.Message
};
// Set the status
var postId = client.Post("pagename/feed", messagePost);
However, I suspect that this is returning the application access_token, not the user access_token (it fails at GET: me/accounts).
you cannot get user token from server-side code (even if you know login/password). You should either:
copy/paste it from Graph API Explorer
Get it from JS SDK client side
Use GetLoginUrl function from FacebookClient to get login URL and redirect the user to that page. After login is completed, facebook will call your function back - and in that function you will be able to the the token. Below are 2 functions (authorize and callback) from my MVC project - but I think you will get the idea.
public ActionResult Authorize(Guid eventId)
{
var redirectUri = ConfigurationProvider.HostingEndpoint + this.Url.Action("AuthorizeCallback", new { eventCode = eventId });
var service = new FacebookClient();
var loginUrl = service.GetLoginUrl(new {
client_id = ConfigurationProvider.FacebookAppId,
client_secret = ConfigurationProvider.FacebookAppSecret,
redirect_uri = redirectUri,
response_type = "code",
scope = "manage_pages, publish_actions, user_photos, publish_stream" // Add other permissions as needed
});
return new RedirectResult(loginUrl.AbsoluteUri, permanent: false);
}
that will redirect user to the Facebook login page. When user enters credentials and presses login, this function will be called (note the code parameter - it will be used to get the token):
public ActionResult AuthorizeCallback(string code, string eventCode)
{
var redirectUri = ConfigurationProvider.HostingEndpoint + this.Url.Action("AuthorizeCallback", new { eventCode = eventId });
var fb = new FacebookClient();
dynamic result = fb.Post("oauth/access_token", new
{
client_id = ConfigurationProvider.FacebookAppId,
client_secret = ConfigurationProvider.FacebookAppSecret,
redirect_uri = redirectUri,
code = code
});
var accessToken = result.access_token;
// update the facebook client with the access token so
// we can make requests on behalf of the user
fb.AccessToken = accessToken;
// now get externded app Token
dynamic extendedToken = fb.Get("oauth/access_token", new
{
client_id = ConfigurationProvider.FacebookAppId,
client_secret = ConfigurationProvider.FacebookAppSecret,
grant_type = "fb_exchange_token",
fb_exchange_token = fb.AccessToken
});
// Get the user's information
dynamic me = fb.Get("me");
}
After that you should call "/me/accounts", find your page and get its token from there.
If you're just trying to post to your own page, an alternative is to use Windows PowerShell and http://facebookpsmodule.codeplex.com. This reduces the operation to a few lines of PowerShell script.

Categories