servicestack and facebook canvas app authentication - facebook

the facebook canvas app gets a "signed_request" parameter when user visits the canvas url via facebook.
How do i use this to authenticate the user on servicestack, so that i get the user session in servicestack.
the user will already be signed up for the app and will have records in the servicestack user repositories.
Should i set the canvas url to /auth/facebook ? with additional ?Continue=/target_url
Will this authenticate the user and send him to the target_url?
Or should i handle the canvas request and then use AuthService to authenticate the user using the "signed_request" param? if this is the case then, how do i proceed with it ?

Here's how I managed the case:
I handled the FB canvas request, receiving the "signed_request" parameter. Then by decoding the BASE64 encoded string (and verifying with HMAC SHA256), I got the FB userId.
if (isMatch)
{
string message = UTF8Encoding.UTF8.GetString(msg);
var output = message.FromJson<Dictionary<string, string>>();
string user = output["user_id"];
OAuthTokens tokens = new OAuthTokens();
tokens.Provider = "facebook";
tokens.UserId = user;
UserSession.IsAuthenticated = true;
((FacebookAuthProvider)AuthService.GetAuthProvider("facebook")).OnAuthenticated(this, UserSession, tokens, new Dictionary<string, string>());
return UserSession.ToJson();
}
I'm not sure whether this is the best way to manually get the user authenticated. But so far, this technique has worked.

Related

Can we get FacebookAccessToken from FirebaseAuth?

With Flutter, I am able to login with Facebook, and later I want to get the FacebookAccessToken because it is needed to correctly get the user photoURL.
Is there a way to get the token from FirebaseAuth? Or I must store this value in my code?
Login part, we have the access token:
FacebookLoginResult result = await new FacebookLogin().logIn(['email', 'public_profile']);
...
FacebookAccessToken accessToken = result.accessToken;
Now, let's say in another Widget, we want to get the user photoURL
final auth = FirebaseAuth.instance;
String url = auth.currentUser.photoURL;
This url must be appended with ?accessToken=<access_token> retrieved during the first step. There is a bug created. But for now, can we directly get it from FirebaseAuth?
The Facebook access token is available from the auth result immediately after the user signs in from the FacebookAuthCredential object as result.credential.accessToken. It is not available from the current user, so if you don't capture immediately after sign-in there's no way to find it later without going back to the Facebook SDK.
Also see:
Can I get a facebook access token from firebase.auth().currentUser?
How to get provider access token in Firebase functions?
Get Facebook/Google access token on Firebase Auth#onAuthStateChanged?

Firebase UI returns idToken that supposedly is not correctly encoded in Facebook login for some users

I am developing an app that verify the custom claims for a user using the following code:
firebase.auth().currentUser.getIdToken().then(idToken => {
// Parse the ID token.
const payload = JSON.parse(window.atob(idToken.split(".")[1]));
// Confirm the user is an Admin.
if (!!payload["admin"]) { // continue
But I realised that some users that logged in using Facebook receives the error below:
DOMException: Failed to execute 'atob' on 'Window': The string to be decoded is not correctly encoded.
These users don't have any custom claim attributed in the app. It looks like that some Facebook's users already receives an idToken from login that is not compatible with atob function. It's not happen to all Facebook users.
Would someone know why some users is receiving an idToken when log in Firebase UI through Facebook ?

HWIOAuthBundle, how to manually authenticate User with a Facebook access token?

I have a website (Symfony2) with HWIOauthBundle used to connect with Facebook and everything works fine.
Now, I'm trying to build an iOS app with Cordova and Ionic framework (AngularJS) and I want to authenticate my user with Facebook :
With $cordovaFacebook, I authenticate my user and get a valid Facebook access token, that's ok
I try to use this access token to authenticate my user on the server-side with HWIOauthBundle :
GET http://..../login/facebook?code=MY_FACEBOOK_ACCESS_TOKEN
Symfony rejects my request with this log :
INFO - Matched route "facebook_login" (parameters: "_route": "facebook_login")
INFO - Authentication request failed: OAuth error: "Invalid verification code format."
So my question is : how can I authenticate my user on both front and back end with Facebook connect?
Thanks :)
I've also been wondering how to implement a server side login with the HWIOAuthBundle.
I didn't find any solution on the web, so I coded the functionnality based on hints I've read on the net.
Basically, you have to :
authenticate the user on your app
make an http request to your server with the Facebook token.
ont the server side, check if the token is for your Facebook app, and retrieve the user's Facebook ID.
Get your user from the DB based on the fetched ID.
Here's my Symfony controller:
public function getSecurityFbAction($token)
{
// Get the token's FB app info.
#$tokenAppResp = file_get_contents('https://graph.facebook.com/app/?access_token='.$token);
if (!$tokenAppResp) {
throw new AccessDeniedHttpException('Bad credentials.');
}
// Make sure it's the correct app.
$tokenApp = json_decode($tokenAppResp, true);
if (!$tokenApp || !isset($tokenApp['id']) || $tokenApp['id'] != $this->container->getParameter('oauth.facebook.id')) {
throw new AccessDeniedHttpException('Bad credentials.');
}
// Get the token's FB user info.
#$tokenUserResp = file_get_contents('https://graph.facebook.com/me/?access_token='.$token);
if (!$tokenUserResp) {
throw new AccessDeniedHttpException('Bad credentials.');
}
// Try to fetch user by it's token ID, create it otherwise.
$tokenUser = json_decode($tokenUserResp, true);
if (!$tokenUser || !isset($tokenUser['id'])) {
throw new AccessDeniedHttpException('Bad credentials.');
}
$userManager = $this->get('fos_user.user_manager');
$user = $userManager->findUserBy(array('facebookId' => $tokenUser['id']));
if (!$user) {
// Create user and store its facebookID.
}
// Return the user's JSON web token for future app<->server communications.
}
I throw the Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException exceptions to handle login errors on my app.
Of course, you really should use https because you will be exchanging sensible information.
I don't know if it's the best way to do it but it works well.
Hope it helps !
Well, I think that Symfony doesn't actually reject your request. Facebook is. I'm not sure if this might help, but I know that a bunch a problems can happen when dealing with the Facebook Auth :
Do you know if the tool sends, along with the code parameter, a redirect_uri parameter ? If so :
Did you check that your redirect_uri HAS a trailing slash at the end ? See this
Silly question, but did you check that your app_id is the same when you got authorized via Cordova ?
Check that your redirect_uri DOES NOT have any query parameter.
Check that the redirect_uri that you use during the whole process is the same all the time.
Overall, it seems that your issue is almost all the time related to the redirect_uri URI format.

FacebookAuthorizeFilter endless redirect

I'm trying to add facebook login to my application. To that extent I'm using a following snippet of code:
[FacebookAuthorize]
public ActionResult About()
{
ViewBag.Message = "Your app description page.";
return View();
}
And I register a filter FacebookAuthorizeFilter.
When I navigate to /Home/About what I get is an endless redirect to
/Home/About?code=AQAPoxl1J-.......
I can login using facebook if I just use OAuth provided in ASP.NET MVC4 project template.
What am I missing?
I delved into the FacebookAuthorize filter code more. The reason the Filter does not work with non-canvas applications is that inside the filter's OnAuthorization method the the method is relying on Facebook's signed_request being present in the POST requset when the user is redirected back to your application. If signed_request is never present the filter will continue to redirect:
...code omitted...
if (signedRequest == null || String.IsNullOrEmpty(userId) || String.IsNullOrEmpty(accessToken))
{
// Cannot obtain user information from signed_request, redirect to Facebook OAuth dialog.
string redirectUrl = GetRedirectUrl(request);
Uri loginUrl = client.GetLoginUrl(redirectUrl, _config.AppId, null);
filterContext.Result = CreateRedirectResult(loginUrl);
}
...code omitted..
An alternative approach may be to create a similar filter that checks for the existent of the code query string parameter. Once code is obtained you may use your application's appId and appSecret to exchange the code for an access token. Once the access token is obtained you may determine which permissions the user has granted and process appropriately.
After hours spent debugging, reflecting, source-code analyzing I came to the conclusion that FacebookAuthorizeAttribute and FacebookAuthorizeFilter can only meaningfully be used in a Facebook Canvas application.

Facebook SDK Login URL Exposing the Client Secret?

I'm currently building a website where I'll offer the users a link to share a photo on Facebook, whereby the application would:
Provide the user with a link to request permissions from Facebook
Redirect back to the website with the access code from the user's acceptance of the permissions
Server-side post the photo to the user's photos
To generate the link for the first step, I'm doing this:
var fb = new FacebookClient();
var options = new
{
client_id = "MY_APP_ID",
client_secret = "MY_APP_SECRET",
redirect_uri = string.Format("http://localhost:51182/Home/FacebookShare?path={0}", Server.UrlEncode(path)),
response_type = "code",
scope = "publish_stream"
};
var loginUrl = fb.GetLoginUrl(options);
Then this loginUrl value is added to my MVC ViewModel and used in a link in the View.
However, I've noticed that the loginUrl contains the client_secret value in clear text. Isn't this a bad thing? Shouldn't users not be able to see the client_secret? Did I go about this the wrong way?
The fb.GetLoginUrl method is rather simple, in that it just adds anything you give it inside the options object as parameters to the URL created.
So take
client_secret = "MY_APP_SECRET",
out of your options object, and it should not show up in the login URL any more.