Auth0 error after failed login attempt - facebook

I am using Auth0 to authenticate users by redirecting them to facebook.
But the problem I am facing is that if a user types in incorrect account credentials the first time and succeeds on the second attempt the redirect does not happen, instead it takes me to "Oops!, something went wrong" page with the following message:
"invalid_request: You probably pressed the back button or there is some issue with cookies, since we couldn't find your session. Try logging in again from the application and if the problem persist contact the administrator."
EDIT: I am using the below Auth0Lock code on the client side.
var lock = new Auth0Lock('<%= auth0.clientId %>', '<%= auth0.domain %>', {
//redirect mode
auth: {
redirectUrl: '<%= auth0.callback %>',
responseType: 'code',
params: {
scope: 'openid' // Learn about scopes: https://auth0.com/docs/scopes
}
},
autoclose: true,
theme: {
logo: 'https://xxxxxx/logo_orange.jpg'
},
languageDictionary: {
title: "test"
}
});
lock.on("unrecoverable_error",function(err) {
console.log(err);
});
lock.on("authorization_error",function(err) {
console.log(err);
});
Once I select Login with facebook I am redirected to facebook url that looks something like link
There if I enter the email/password incorrectly the first time the page refreshes and on the second try if I succeed,instead of taking me back to my app the auth0 generic error page => doc shows up with the error I mentioned at the top.On the server side passport seems to correctly authenticate the user.
PS: Chrome is taking me to a login page which has a login form on top and center but firefox just has login at the center of the page.For chrome if I use the top login form and has a failed login attempt on second successful attempt I am taken to my facebook page i.e no redirect happens.

There's at least one issue and that one is a Facebook problem. Their login page is showing two login forms:
The TOP form has an action equal to:
https://www.facebook.com/login.php?login_attempt=1&lwv=100
while the CENTER one has:
/login.php?login_attempt=1&next=https://www.facebook.com/v2.4/dialog/oauth?redirect_uri=https%3A%2F%2Flogin.eu.auth0.com%2Flogin%2Fcallback&state=[state]&response_type=code&client_id=[client_id]&ret=login&logger_id=1bf0be0d-4b64-43a6-b112-79a30100fa5b&lwv=100
This means that submitting the top form does not maintain enough information to be able to return back to your application. Now, there's still the issue of the Auth0 generic page being shown, but that one I'm unable to reproduce. If you think it's worthwhile, then do upload an HAR for review, even one where you strip all cookies might help.
Update:
Looked at the HAR, the second issue seems to be caused by an authentication request to Facebook that does not pass through Auth0. There's a request to your application, but that one does not complete an then there's this second request that will trigger the Auth0 error page.
Expected flow:
https://test.auth0.com/authorize
https://www.facebook.com/dialog/oauth
https://www.facebook.com/login.php (user authenticates here)
https://www.facebook.com/v2.8/dialog/oauth
https://test.auth0.com/login/callback
https://localhost:8080/callback
What's causing the error generic page, before your localhost request completes another request is issued:
https://www.facebook.com/v2.8/dialog/oauth
https://test.auth0.com/login/callback (generic error page shown here)
The error is caused because https://test.auth0.com/login/callback is called without first going through https://test.auth0.com/authorize to setup the authentication transaction state.
Given the request to your application localhost is marked as incomplete I would start looking in your code to see if there's any reason for that request to not complete.

Related

Facebook API error code 190, subcode 460 in Meteor app even after refreshing login

I use accounts-facebook in Meteor 1.4.3.2 to allow my app's users to log in via Facebook. The app also makes other Facebook API calls using the Facebook token accounts-facebook stores in the user document.
Sometimes, when I try to make a call, I get an error:
{
message: 'Error validating access token: Session does not match current stored session. This may be because the user changed the password since the time the session was created or Facebook has changed the session for security reasons.',
type: 'OAuthException',
code: 190,
error_subcode: 460,
fbtrace_id: '...'
}
Facebook says users will need to log in again. I built a flow to fix this problem. When we get a 190/460, we set the services.facebook.accessToken property in their user document to false and email them a link to a page with a "Refresh Facebook Login" button which simply logs them in to the app again via Facebook.
The flow appears to work. I can see the accessToken gets set to false. When I click through on the link in the email and then click the "Refresh" button, I get a token that is different from the previous token. However, when the app tries to make another FB API request, it gets the same 190/460 error with the new token.
If the fix for 190/460 is to have the user log in again, why do I continue to get the error after the user has refreshed the token?
I had a similar issue and solved it going to Facebook developer page
-> Messenger option from the left menu
-> Configuration
then scroll to "access tokens", click "generate token" button and copy that token to your code.
For example in php looks like
$accessToken = 'EAAKHOkhtsDABAJgyp....';

Redirect after user has logged in

I'm pretty new to Angular, and right now I'm just trying to get all my routes set up and working as I'd like.
Setup:
When a user navigates to certain pages (/settings for this example) the app should check if there is a user already logged in. If there is continue as usual. Otherwise the user should go to the login page (/login).
What I'd like:
After the user has successfully logged in they should go to the page they were originally trying to get to (/settings)
My question:
Is there an "Angular way" to remember where the user was trying to go to?
Relevant code:
app.js
.when('/settings', {
templateUrl: '/views/auth/settings.html',
controller: 'SettingsCtrl',
resolve: {
currentUser: function($q, $location, Auth) {
var deferred = $q.defer();
var noUser = function() {
//remember where the user was trying to go
$location.path("/login")
};
Auth.checkLogin(function() {
if (Auth.currentUser()) {
deferred.resolve(Auth.currentUser());
} else {
deferred.reject(noUser());
}
});
return deferred.promise;
}
}
})
login.js
$scope.submit = function() {
if(!$scope.logInForm.$invalid) {
Auth.login($scope.login, $scope.password, $scope.remember_me)
//go to the page the user was trying to get to
}
};
Much thanks to John Lindquist for the video which got me this far.
First off, you do not want to redirect the user to a login page.
An ideal flow in a single page web app is as follows:
A user visits a web site. The web site replies with the static assets for the
angular app at the specific route (e.g. /profile/edit).
The controller (for the given route) makes a call to an API using $http, $route, or other mechanism (e.g. to pre-fill the Edit Profile form with details from the logged in user's account via a GET to /api/v1/users/profile)
If/while the client receives a 401 from the API, show a modal to
login, and replay the API call.
The API call succeeds (in this case, the user can view a pre-filled Edit Profile form for their account.)
How can you do #3? The answer is $http Response Interceptors.
For purposes of global error handling, authentication or any kind of
synchronous or asynchronous preprocessing of received responses, it is
desirable to be able to intercept responses for http requests before
they are handed over to the application code that initiated these
requests. The response interceptors leverage the promise apis to
fulfil this need for both synchronous and asynchronous preprocessing.
http://docs.angularjs.org/api/ng.$http
Now that we know what the ideal user experience should be, how do we do it?
There is an example here: http://witoldsz.github.com/angular-http-auth/
The example is based on this article:
http://www.espeo.pl/2012/02/26/authentication-in-angularjs-application
Good luck and happy Angularing!

Facebook PHP SDK usage stand alone - how do the Facebook sessions/cookies work?

I'm utilizing the Facebook PHP SDK on its own. I do not want to use the JS SDK at all.
Because getUser(); from the SDK can return a user id even if the user is not logged in, I have opted for using a try/catch statement to check if the user is logged in.
try
{
$me = $CI->facebook->api('/me');
$CI->our_fb['is_fb']='YES';
echo "hello";
}
catch(FacebookApiException $e)
{
echo "catch";
}
This statement is included in the global include file of all of my files (for simplicity).
So, depending on the situation, I generate a Facebook login URL. The expected functionality is that the user logins to Facebook, authorises the app, is returned to the redirect URI set in the login URL at which point the try statement will execute, and $CI->our_fb['is_fb'] will be set.
This is however not happening.
If the user is already logged into Facebook and the app is authorised, it works perfectly. SUCCESS
If the user is not logged into Facebook, once redirected the variable is not set. FAILURE
If the user is logged in but the app is NOT authorised after redirect the variable is not set. FAILURE.
In the latter two cases if you simply refresh the page, the variable is set - SUCCESS. Refreshing the page is however unnecessary/pointless extra effort.
My problem is that if you need to login to FB/or authorise the app e.g the first time you login with FB, you have an additional unneeded refresh, and I don't know why.
I suspect it is something to do with the cookie/session? Which saves the access token that I assume is returned/passed to the SDK automatically not being set at the same time?
Anyone got any ideas?
If you're having an app on facebook (tab or canvas). PHP SDK only get the User ID on initial loading of a page because a signed_request is sent with the request to your app.
But, when the app refreshes, the signed_request is lost (as it's facebook who send it).
So, in this case, you can append the signed_request to every URLs your use in your app - but that's really not optimal as the signed_request won't be regenarated - neither refreshed.
Your only real option is to rely on the JS SDK to set cookie correctly and allow getUser to work as expected. This is required because you're considered as a third-party app in Facebook (being in an iframe) and most browser will block you from setting cookies - so you need a work around handled by the JS SDK for you. You can search for cross-domain cookies or third-party cookie for explanation about the workarounds, but these workaround only work via JS scripting and iframe management.
Also, be sure to setup the JS SDK correctly: channel file, cookie allowed, and send P3P headers (for IE).
You can also check this related question: A proper approach to FB auth
About website, the same mostly stays (but you have no signed_request). At this point, seriously consider using the JS SDK as it's way easier. Or else, you can make sure your app flow follow these guidelines: https://developers.facebook.com/docs/concepts/login/login-architecture/
The way I am seeing this is, you are trying to avoid that refresh if the user is not logged in and precedes to log in after the page has initially loaded.
So what you can do is make an ajax request to another page on your site, say for example id.php, which just loads the php sdk and echo $userid; and then you can grab the user id after login without the refresh.
Basically the cookie is used to save the signed request and session is used to save 'state', 'code', 'access_token', 'user_id'. If the above are present PHP SDK uses them, no matter if they are valid or not.
I think your problem lies in the CODE sent by facebook. Specifically these lines in base_facebook.php:
if ($code && $code != $this->getPersistentData('code')) {
$access_token = $this->getAccessTokenFromCode($code);
...
protected function getAccessTokenFromCode($code, $redirect_uri = null) {
if (empty($code)) {
return false;
}
if ($redirect_uri === null) {
$redirect_uri = $this->getCurrentUrl();
}
...
Because CODE is issued for specific url sometimes there is such situation: Visitor arrives on www.example.com. He givies permissions and is redirected to example.com/login. But the code is not valid there, so the getUserAccessToken returns false. When you refresh the page you get same urls and everything's fine.
You're on the right track of not using getUser() because as I wrote above it's taken from the session if available.

Graph Request Only Works With My Facebook Account

I have a web page which asks the user to log in and then proceeds to get JSon via Graph for a particular Facebook group. It builds the Uri dynamically by taking the access_token that is returned after login. It works fine when I do this, but if I try to log in with a different account, no data for the feed is returned.
One hint in this problem is when the facebook dialog screen appears, it only asks for my username/password. It doesn't ask go to the usual screen where Facebook asks for you to give permissions for "Basic Information" etc. It's just a username/password screen and then I go straight in.
This is the login code:
function login()
{
FB.login(function (response)
{
if (response.authResponse)
{
// connected
var authResponse = response.authResponse;
access_token = authResponse.accessToken;
refresh();
} else
{
// cancelled
}
});
}
One hint in this problem is when the facebook dialog screen appears,
it only asks for my username/password. It doesn't ask go to the usual
screen where Facebook asks for you to give permissions for "Basic
Information" etc. It's just a username/password screen and then I go
straight in.
This is because you've already authorized the app, so once you login it will take you straight to the app.
It works fine when I do this, but if I try to log in with a different
account, no data for the feed is returned.
Well the limited view of code you posted is fine, so something else is the problem. First debug step is to get the access token for that different account, and check the debugger to see if its tied to the appropriate user and scope.

Facebook redirect after login

I have read a number of questions and answers, including this one on StackOverflow and none works. My question to all responses I have seen are 'does it work in Safari?'.
I am trying to get this to work with Safari. It works on Chrome and Firefox fine. But in Safari the login screen just freezes and I get the "Unsafe JavaScript attempt to access frame with URL" log message.
I have a canvas app. I want to log the user in and redirect them to a page once they have logged in. I am trying to redirect directly after login. I have tried
setting window.top.location to a facebook url (with some data passed to a signed request as the all_data argument)
setting window.location to a URL with the same domain as my app.
subscribing to the auth.login event and putting the redirect there
putting the redirect in the callback to login
None of these works for Safari. I'm starting to think that there's no way to do it.
function doSomething()
{
FB.login(
function(loginResponse)
{
if (loginResponse.authResponse)
{
window.top.location = "my url"
}
},
{
scope:"some,scope"
}
);
}
}
In response to Nitzan Tomer, here is the equivalent code which doesn't work with Safari but does work with others:
function myThing()
{
FB.login(function(loginResponse)
{
if (loginResponse.authResponse)
{
FB.api('/me', function(response)
{
window.location = "http://my_app.com?x=" + response.xyz;
});
}
},
{
scope:"scopes"
}
);
}
This is not much of a solution to your problem, but more of a "workaround", though it still uses window.top.location but not from a callback so maybe it will work (I'm just not sure where the callback is executed, since it's the fb sdk that executes it, maybe they call it from the fb iframe inside your iframe).
Instead of using client side authentication, you can use the server side flow.
The entire process is happening on the top window, since it starts by you redirecting the user to the oauth dialog using window.top.location.
When the process ends facebook redirects the user to your redirect_uri, and there you can simply redirect the user where ever you want.
I hope this will help.
Also, you should be aware that in the Facebook Platform Policies it states:
13 . The primary purpose of your Canvas or Page Tab app on Facebook must not be to simply redirect users out of the Facebook experience
and onto an external site.
It turns out the problem was occurring slightly earlier in the login process and the callback never got called. I did set a breakpoint in the callback (which wasn't called) but I thought the breakpoint might not work for some reason (perhaps because it was being executed in the context of another window).
Anyway, the problem was that the channel file (which the docs seem to suggest are optional) wasn't working properly, and this caused a problem with Safari but not with other browsers.