I'm trying to add the ability to post to a users wall from a site I'm developing.
I've got some code in place using the Microsoft C# Facebook SDK. It checks if the current user is authenticated, if not, redirects to the OAuth page. If the user is authenticated, it tries to post to their wall:
CanvasAuthorizer auth = new CanvasAuthorizer();
bool authorized = auth.FacebookWebRequest.IsAuthorized(new string[] { "publish_stream" });
if (authorized)
{
FacebookClient client = new FacebookClient();
client.AccessToken = auth.FacebookWebRequest.AccessToken;
Dictionary<string, object> args = new Dictionary<string, object>();
args["message"] = "This is a test.";
args["name"] = "";
args["link"] = "http://subdomain.domain.lom/";
args["description"] = "Development site.";
client.Post("/me/feed", args);
}
else
{
long appId = {APP_ID};
string returnUrl = "http://subdomain.domain.com/share";
Response.Redirect("https://www.facebook.com/dialog/oauth?client_id=" + appId.ToString() + "&redirect_uri=" + returnUrl + "&scope=publish_stream");
}
The first time you load, it sees that you're not authenticated and redirects you to the Facebook auth page.
However, when it tries to return to my site, it goes into a redirect loop.
It looks like what is happening is that when it returns from Facebook, it does the authentication check, but it's saying the users isn't authenticated. This then redirects to the Facebook login again, which knows the user is authenticated, so returns to my site, causing the loop.
I'm developing on my local machine at the moment, http://subdomain.domain.lom/, which isn't accessible from the outside world.
My Facebook App settings are:
App Domain: domain.lom
Site URL: http://subdomain.domain.lom/
I was under the impression that it doesn't matter if you're working locally?
Sandbox mode
I would suggest creating second Facebook application (in terms of Facebook app id) for development and testing with sandbox mode turned.
With the testing app you can use the same code with different settings on limited number of users hidden from anyone else (really useful).
Here are some links:
Application Security from Facebook docs.
How do you limit a Facebook app to a small number of people during testing? from stackoverflow.com.
Possible bugs
Try encode returnUrl value.
It it won't work you have to debug it :(. My first guest is Facebook authorized you for another domain.
Something else to look at would be for IE to work without that infinite redirect looping, it needs to see a p3p policy from your web server.
Check in your web.config for the p3p header. If it's not there, then you can add one to make IE happy.
See http://www.hanselman.com/blog/TheImportanceOfP3PAndACompactPrivacyPolicy.aspx
Related
I want to create a ASP.NET project (Single Page Application) and activate Facebook login. But now 2 days later I can not get it work!
I have:
Visual Studio 2015
This is my steps:
Create a new ASP.NET 4.6 (Single Page Application) -project.
Uncomment this and added appid and appsecret (fake here):
app.UseFacebookAuthentication(
appId: "5675675657567567",
appSecret: "346n3636n34n6346n346n346n346n346");
Created a new Facebook app with this settings:
-Client OAuth Login: on
-Web OAuth Login: on
-App Domains: localhost
-Valid OAuth redirect URIs: http://localhost:63496/signin-facebook
And added the real appid and secret.
When I click on the facebook login button, i can login to facebook but i just redirect back to my homepage and nothing happens, I am not logged in at all. Next time I click on the facebook login button it seems that i am already logged in on facebook so I just redirect back again directly.
So the question is, how can I login to my homepage via Facebook? Can I not login correctly in debug-mode?
Simply update the package Windows.Owin.Security.Facebook to the latest version (3.1.0)
Further, in the Facebook application update the "Valid OAuth redirect URIs" to "http://localhost:xxxx/signin-facebook" (where xxxx represents the port number) every thing works...
Interesting. I tried setting up OATH2 with Facebook for login to my MVC5 app. Got the appId AppSecret and plugged them in. Ensured SSL was enabled. But Facebook does not seem to authorize and I get into the same loop you mention.
I then proceeded to set up the same with Google, and it worked just fine. The problem seems to be with the Facebook API (.. or something :) )
1) Need to install "facebook" nuget package in c# project.
2) Must to create facebook app from https://developers.facebook.com/ and store appId and appSecret in your application.
3) Execute below code for facebook authorization and call "FacebookLogin" method on action event.
[HttpPost]
public string FacebookLogin()
{
try
{
// Instantiate the Facebook client
var oauth = new FacebookClient();
var fbLoginUrl = oauth.GetLoginUrl(new
{
client_id = "Enter ApplicationID",
client_secret = "Enter ApplicationSecret",
redirect_uri = "Enter RedirectUri",
response_type = "code",
scope = "manage_pages,email" // Add other permissions as needed
});
var fbloginUri = fbLoginUrl.AbsoluteUri;
Session["ClientId"] = "Enter ApplicationID",
return fbloginUri;
}
catch (Exception)
{
return null;
}
}
I currently have a website where I am trying to implement the OAuth server framework. The website is currently a combination of Web Forms (not MVC) and Web API 2. For the purposes of what I am trying to do, we cannot change the overall architecture of the system.
So far, I have OAuth working via the Web API for validating clients, generating access tokens, and handling refresh tokens.
The last piece I am trying to implement is the Authorize Code workflow. This will allow us to grant access to our application so integration tools can access our APIs without having to locally store the user credentials.
My understanding of how it should function is the following:
User is directed to the AuthorizeEndpointPath that I define in the Startup.Auth file
User either sees a login page (if they don't already have an authentication cookie for the website), or they see a special page where they have to grant permission to access the account (similar to what Google has)
Once the user clicks the "grant" button, the OWIN middleware will process the request, and redirect them back to the original client URL that requested access
However, after all of my configuration, whenever I access the AuthorizeEndpointPath directly, the "grant access permission" page is never actually displayed.
I've ensured the following configuration, but there isn't much documentation on what the correct configuration is.
var oAuthServerOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/api/token"),
AuthorizeEndpointPath = new PathString("/LoginAuthorize.aspx"),
//AuthorizeEndpointPath = new PathString("/api/authorize"),
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(10),
Provider = new ApiAuthorizationServerProvider(),
RefreshTokenProvider = new ApiRefreshTokenProvider(),
AuthorizationCodeProvider = new ApiAuthoirzationCodeProvider()
};
Currently the "AuthorizeEndpointPath" property maps to an actual page, where I ask the user confirmation, but that page is not being displayed at all
Through debugging, I can see the framework hits the following method even before the authorization page would be loaded
ValidateClientRedirectUri(OAuthValidateClientRedirectUriContext context)
I have tried to overload that method, and one of 2 things happens. If I make a call to context.Validated();, the user is immediately redirected without the authorization page being displayed. If don't "validate" the redirect URI, then a blank page is displayed indicating an "invalid_request".
So the big question is how do I actually make OWIN display my custom authorization page?
When the authorization page is finally displayed, what would I need to do when the user clicks on the "grant" button. Is there any configuration I need to setup, or any calls to OWIN I need to make?
Also, how do I ensure the user authenticates before that page is displayed? Do I simply have my code redirect the user to the login page if they are not logged in? If so, how will OWIN handle the real redirect back to the client (if the user would be redirected to the authorization page once they login)?
Finally, once this is all configured properly, will I still be able to support the current OAuth workflow I have of allowing clients to manually pass in their credentials for the "token" API? The reason I ask is because we also have mobile apps that have their own sign-in screen, and will be using OAuth to connect (in addition to other web-based clients).
I had a question that turned out to be similar to yours.
So, after quite some searching online, I got some success by searching github. Apparently, OAuthAuthorizationServerProvider offers AuthorizeEndpoint and that method should be used for both "Hey, you're not authorized, go log in you!" as well as for "Ahh, okay you're cool, here's an authorization code.". I had expected that OAuthAuthorizationServerProvider would have two separate methods for that, but it doesn't. That explains why on github, I find some projects that implement AuthorizeEndpoint in a rather peculiar way. I've adopted this. Here's an example:
public override async Task AuthorizeEndpoint(OAuthAuthorizeEndpointContext context)
{
if (context.Request.User != null && context.Request.User.Identity.IsAuthenticated)
{
var redirectUri = context.Request.Query["redirect_uri"];
var clientId = context.Request.Query["client_id"];
var authorizeCodeContext = new AuthenticationTokenCreateContext(
context.OwinContext,
context.Options.AuthorizationCodeFormat,
new AuthenticationTicket(
(ClaimsIdentity)context.Request.User.Identity,
new AuthenticationProperties(new Dictionary<string, string>
{
{"client_id", clientId},
{"redirect_uri", redirectUri}
})
{
IssuedUtc = DateTimeOffset.UtcNow,
ExpiresUtc = DateTimeOffset.UtcNow.Add(context.Options.AuthorizationCodeExpireTimeSpan)
}));
await context.Options.AuthorizationCodeProvider.CreateAsync(authorizeCodeContext);
context.Response.Redirect(redirectUri + "?code=" + Uri.EscapeDataString(authorizeCodeContext.Token));
}
else
{
context.Response.Redirect("/account/login?returnUrl=" + Uri.EscapeDataString(context.Request.Uri.ToString()));
}
context.RequestCompleted();
}
Source: https://github.com/wj60387/WebApiOAUthBase/blob/master/OwinWebApiBase/WebApiOwinBase/Providers/OAuthServerProvider.cs
You create a separate login page at /account/login. What this does is sign the user in. If your WebAPI uses cookie-based authentication, you can just redirect the user back to the AuthorizeEndpoint again. If you use access tokens, your login page has to make a request to `AuthorizeEndpoint' with the access token to obtain an authorization code. (Don't give the access token to the third party. Your login page requests the authorization code and sends that back.) In other words, if you use access tokens then there are two clients involved in this flow.
I want to post messages in my friends wall using a program. I will post the message using my asp.net application. I tried facebook's graph api. the problem is every time I have to use facebook provided login dialog to get the access token which requires manually enter username and password. Therefore I created a facebook app and obtained appid and app secret string. I am trying the below code to post a message in my wall first. I am getting the below exception.
var fb = new Facebook.FacebookClient();
dynamic tokenInfo =
fb.Get(
String.Format(
"/oauth/access_token?client_id={0}&client_secret={1}&grant_type=client_credentials",
"1234567890",
"2bebebdf4709xxxxxxxxxxxxxxx"));
fb.Post("/100006xxxxxx/feed", new { message = "My Message" });
Error :
This API call requires a valid app_id
Your friend must authorize your app and they need to grant the "publish to feed" privilege to your app. To get this going, you need to have the user authorize your app via "Facebook Connect". Use Facebook Connect to trigger the "authorize your app" process. Once the app is authorized, the facebook api should recognize that your friend is logged into facebook (facebook api uses cookies to know that the user is logged into FB or not). Only then will issuing this command work. Hope this helps.
var fb = new FacebookClient(acctocken);
var args = new Dictionary<string, object>();
args["Message"] = "Hai Dear";
fb.PostAsync("[friend id]/feed", args);
Hope Its Help You
I have a Facebook canvas application written on asp.net mvc. I can't see what's going on in facebook.
I have client-side code that loads FB user picture:
FB.api('/' + userId, { fields: "id,link,name,picture" }, function (user) {
$('img[data-fb-user-img]', subjectVoterElement).attr('src', user.picture.data.url);
});
One day it responds picture url in user.picture, another day - in user.picture.data.url so i have errors time to time. Why FB gives different respond structure?
2.
To authorize FB user in my app i use facebook cookie being sent to my app server. Then i extract value from it, then parse the value with ParseSignedRequest method and exchange obtained code into token.
HttpCookie fbCookie = filterContext.RequestContext.HttpContext.Request.Cookies[
String.Format("fbsr_{0}", System.Configuration.ConfigurationManager.AppSettings["FB_Id"])];
string code =
((dynamic) FacebookService.FacebookService.Client.ParseSignedRequest(fbCookie.Value)).code;
using (var webClient = new WebClient())
{
var result = webClient.DownloadString(
String.Format(
"https://graph.facebook.com/oauth/access_token?client_id={0}&redirect_uri=&client_secret={1}&code={2}",
FacebookService.FacebookService.Client.AppId,
FacebookService.FacebookService.Client.AppSecret,
code
)
);
Sometimes i get authorization error saying the code is expired or specified user has logged off from facebook. In fact, i logged off a hour ago and since that moment this have already been worked successfull. Also, the facebook cookie expiration time is set long enough and hasnt come yet.
Does anyone have the same problem? Thanks
I am not sure if this is the issue with #1 or not but I have had issues so I will just throw it out there. There are actually at least two different types of facebook users (could be more):
Regular facebook users that have accounts like you and me
Accounts that are just setup for a facebook page
How to create a facebook account that is just for a page?
Step 1: Logout of your facebook account
Step 2: Go here: http://www.facebook.com/pages/create.php
Step 3: Setup a page for a fake business or whatever type of page you
want to test with
Step 4: Select I do not have a facebook account and create an account
with a new email address
Now try your application with your regular user and with this facebook page only user. Like I said, I am not sure if this is your problem or not but I have had a bunch of other problem with facebook page only accounts so it is could be worth a try.
I am looking at using the facebook SDK and I am wondering first what version should I be using?
It looks like some major changes are happened from 4.2 to 5(currently still in beta). Should I go ahead and use the beta? Anyone have any ides when it will be out of beta?
My second question is how can I use it for authentication.
Right now I am using DotNetOpenAuth to do all my openId authentication for my site. I am using there sort of plugin for facebook authentication(oAuth) however I am planning to use more facebook features on my site so I think it is kinda pointless to use this plugin and then the sdk libary when the library seems to be able to do it all.
Anways how do I do authentication with the sdk library. I want to have a button on my login page that they click it goes off to facebook they become authenticated and I get some request back saying that they where authenticated and then I give them a cookie and let them in.
All the tutorials I seen to have it that your just using facebook as your only authentication method but of course for me I have openId, facebook and twitter.
http://facebooksdk.codeplex.com/wikipage?title=Getting%20Started%20with%20an%20ASP.NET%20MVC%203%20Website&referringTitle=Getting%20Started
I use the Facebook SDK, and my advice for you would be to use the beta
The reason is because Facebook is changing and depreciating a lot of the Old REST interface and making Graph API the only way to access data. So, to be future proof, the latest and greatest is the way to go.
Now, it is a beta, so everything isn't 100%. If you need stability and don't mind making changes, then use the stable version and then upgrade later.
As for authentication, the process to authenticate is pretty simple.
you need your authURL:
string authURL = #"https://graph.facebook.com/oauth/authorize?client_id=" + Settings.appId + "&redirect_uri=" + redirectUrl + permissions
where appId is your Facebook Application ID (you get it when you register your app with Facebook), the redirectUrl is the URL that you want Facebook to send you the challenge token, and your permissions are the list of things you want to access with your Facebook authentication Token
You make a popup or whatever that browses to that URL. The user will login to facebook (if they haven't already) and then they will be presented with the app authorization screen (if they haven't already authorized the app). Once they authorize (or imidiately if they already authorized), the page will be forwarded to the redirectUrl that you provided. In the URL, there will be a GET variable called code that will contain the challenge string. You take that challenge code and add it as a query variable to another URL that is in the form of:
https://graph.facebook.com/oauth/access_token?client_id=YOURID&redirect_uri=http://www.facebook.com/connect/login_success.html&client_secret=YOURSECRET&code=THATCODE
That URL will return the authentication key...
Phew! That's quite the process.... If done manually :) Now that you know a little more about what's going on, you can appreciate what the SDK does for you.
To authenticate with the SDK, Just follow the 19 simple steps as outlined in this link
Easy huh?
Regarding 4.2 vs 5.0 BETA I guess you need to decide whether you want to use a BETA version or a stable version. I am sure they have a changelog in their BETA Release you can look at for the changes since the older version.
Regarding authentication using Facebook. I have a project where I support standard Forms authentication and accounts creation as well as Facebook login. In my AccountController I have one action for Forms login and one for Facebook login.
To configure the Facebook assembly you can follow the tutorial you have posted, then you can put a Facebook button on your page and similar code to begin the authentication process:
<script type="text/javascript" src="http://connect.facebook.net/en_US/all.js"></script>
<script type="text/javascript">
$(function () {
FB.init({ appId: '<%= FacebookSettings.Current.AppId %>', status: true, cookie: true, xfbml: true });
$('#fbLoginButton').click(function () {
FB.login(function (response) {
if (response.session) {
// Success - execute our facebook login action.
window.location = "<%= Url.Action("FacebookLogin", "Account") %>";
} else {
// user cancelled login or failed
}
}, { perms: 'email' });
return false;
});
});
The facebook aciton works by:
Was Facebook Authentication successful?
Do we have a user with the Facebook Id as a username in the system?
If not create a user, populate name, email, etc from the Facebook data
Set the Forms authentication cookie
Pseudo code:
FacebookApp facebook = new FacebookApp ();
if (facebook.IsAuthenticated) {
string userName = facebook.UserId.ToString();
if (UsersRepository.ByUserName(userName ) == null) {
// Create a User using the Facebook name, email, etc data
}
FormsAuthentication.SetAuthCookie (userName , true);
}
So the idea is that I delegate the authentication to those 3rd party services and then create a user on my system with the information I can fetch from them. Also in my project, because I want the user to set/very some preferences after the account is created I redirect them to the page where they can do that.
P.S: A tip regarding running your web project locally in Visual Studio. You can create a private Facebook App with "Site URL" set to e.g. "http://localhost:4911/" and use that appId. This will allow you to play with Facebook locally.