Handle an express redirect from Angular POST - javascript

I'm using Expressjs as an API and I'm using angular to hit that POST. I would like to respond to the redirect that express is sending. Success from my Angular POST returns a HTML of the page I intend to redirect to but nothing happens on my DOM. I can see that my redirect is working in my network traffic, and that console.log data, below contains the DOM of the redirected page.
How can I refresh the DOM, to reflect this successful POST, or handle the "redirect"?
ANGULAR CODE:
$http({method: 'POST', url: '/login', data:FormData}).
success(function(data, status, headers, config) {
console.log(data)
}).
error(function(data, status, headers, config) {
});
$scope.userName = '';
Expressjs API:
app.post('/login', function(req, res){
var name = req.param('name', null); // second parameter is default
var password = req.param('password', "changeme")
// Lots Authenticationcode
// returns succesfful login
res.redirect('http://localhost:3000/');
}); // end app.post
console.log(data) (from Angular POST success)
returns the HTML of the page I intended to redirect to

AngularJS is meant to work as a client-side framework coupled with (mostly) RESTfull APIs. Your login API isn't supposed to return a HTML, it is supposed to return the instruction to redirect. So in your case you should simply call $location.url('/') in your $http success callback, which would use the Angular router to "redirect" to '/' (the root URL).

Related

How to redirect a user in angular.js using access token mechanism?

This is the process flow:
On the front end, the user logs in by providing username and password.
The server will respond a token to the user if the credentials are correct.
Now the user should be redirected to the homepage (PROBLEM HERE). I have set the token in the header by this code: $http.defaults.headers.common['X-Auth-Token'] = token;
Also, when I do a http.get method, I am getting an "OK" response
$http({ method: 'GET',
url: '/home/',
headers: {
'X-Auth-Token': token
}
}).then(function successCallback(response) {
console.log(response.statusText);
}
Now, the issue is that when I use $window.location.href = "/home", the server responds "unauthorized token" because the server always expects a token in the header with each request. In the command window.location.href, I cannot set the header.
What is an alternative to redirect the user to the homepage. Assume the server always checks the header for the access token.
Thanks in advance!!!
AFAIK if u are using HTTP redirect like setting the window.location.href, there is no way to custom headers. Neither can u do that when using a form post.Use cookies instead for these purpose.
Ajax(XMLhttpRequest) may be the only one that supports setting custom headers.
If u don't mind using angular routing(however doing this may expose some logic in js code which should only be exposed to authenticated user), u may add an resolve for resolveRedirectTo in which make an ajax request to check the authentication status every time route changes.
EDIT
For using angular routing, the basic thinking is to ask user to do send ajax request with custom headers to server to check if he/she is authorized to visit that page. Check out the following code and this fiddle
app
.config(['$routeProvider',function ($routeProvider) {
$routeProvider.
when('/home', {
templateUrl:"home.html" ,
controller: 'MainController',
resolve:{
isLogin:function($q, $http,$location) {
var deferred = $q.defer();
//verify the user via an ajax request every time the user attempts to visit `/home`
//here since u have already set the custom headers for $http upon signing in, the next request will be with the header.
//the follow test url will return {isLogin:true}
$http({method: 'GET', url: 'http://echo.jsontest.com/isLogin/true'})
.success(function(data) {
if(data.isLogin){
deferred.resolve(data.isLogin); // no need to redirect
}
else{
$location.path("/guest");// redirect to guest page if not authorized
deferred.reject();
}
})
.error(function(data){
//error
$location.path("/guest");
deferred.reject();
});
return deferred.promise;
}
}
}).
when("/guest",{
templateUrl: "guest.html",
controller: 'GuestController',
})
.otherwise({redirectTo:'/guest'})
}]);

Passport Login without Redirect Security (Node.js)

I am currently making a web application where when the user logs in, I don't want the page to be redirected -- instead, I want the client to simply update the current page its on (I thought about using AJAX requests). I am using a nodejs backend with passport as my authentication middlewear.
CLIENTSIDE:
I currently have the page that i want to check login status to simply call a function onload:
function fetchLoginStatus(){
var request = new XMLHttpRequest();
request.open("GET", "/checkLogin.json", false);
request.send();
}
SERVERSIDE:
In the server, i have the following route:
app.get('/checkLogin.json', passport.authenticate('local-login'), function(req, res){
res.send(req.user.username);
});
Back on the Client Side, I check this response data to see if a user has successfully logged in.
Is this safe? Using JSON to authenticate? And is there a better way to accomplish this?
I can't see in your code that you actually send credential information to your server. assuming that "/checkLogin.json" is not a JSON object but the name of the http endpoint, you must send credentials information (usually, user and password) using the body of a POST request, as dylants says. example:
//client side, angular.js: post with user, password
$http({
method: 'POST',
url: '/api/login',
data: {usr: usr, psw:psw}
}).
success(function(data, status, headers, config) {
$rootScope.authcode = self.ROLE_AUTH;
$http.defaults.headers.common.Authorization = data.tkn;
cb(null);
}).
error(function(data, status, headers, config) {
console.log("error loggin in", data, status);
cb("AUTHENTICATION_ERROR");
});
then, in the server side, you use the credential information to validate with some backend service (usually a BD) and returns an authentication token:
exports.login = function(request, reply){
var usr = request.payload.usr;
var psw = request.payload.psw;
var token = MuAuth.login(usr, psw, function(token){
if(token != null){
reply({tkn:token});
}else{
var error = Hapi.error.badRequest('auth error');
//return 401 if authorization fails
error.output.statusCode = 401;
error.reformat();
reply(error);
}
});
};
Notice that in the client side, if the authentication call is successful, the authtoken is added to the http default headers. in this way, it will be included in all future calls to the server.

Angular $http request in the controller does not work

I have the following controller. It works all fine (it parses the data and sends them into the view). The only problem I have is that it does not send $http request. Here is the code block of controller (i just send a test $http without any value from the view just to test it works or not, which does not work):
(It's also worth mentioning that I check via browser's console to see if any ajax request is sent or not)
// Controller
LoginApp.controller("RegisterController", function($scope, $http, registerService){
var username = null;
var password = null;
$scope.registerSubmit = function(){
username = $scope.register.username;
password = $scope.register.password;
};
//registerService.CheckUser();
$http.post('server.php', {name : 'something'})
.success(function(data, status, header, config){
return data;
})
.error(function(data, status, header, config){
return data;
}); // end of $http request
});
EDIT: I have edited what #JoshBeam has recommended, passing data to the post(), but it does not change anything.
You need to pass data along with the HTTP request. According to the AngularJS documentation, it is in this format: post(url, data, [config]);
Thus:
$http.post('server.php', /* your data */);

Unable to get authenticated using Redmine REST API

I am building a mobile application for Redmine. So, to get data from the Redmine server, I need to authenticate the user by passing his password and username. In Redmine API documentation, two methods are mentioned for authentication.
using your regular login/password via HTTP Basic authentication.
using your API key which is a handy way to avoid putting a password
in a script. The API key may be attached to each request in one of
the following way:
- passed in as a "key" parameter
- passed in as a username with a random password via HTTP Basic
authentication
- passed in as a "X-Redmine-API-Key" HTTP header (added in Redmine
1.1.0)
I tried to send a get request as follows, I can see the issue list in response to the Get request in browser. But the success callback is not triggering.
var url= "http://username:password#redmine.qburst.com/issues.json";
$http({
method: 'JSONP',
url: url
}).
success(function(data, status) {
console.log(data);
}).
error(function(data, status) {
console.log("Error "+status);
});
The following error is coming in console.
SyntaxError: missing ; before statement
{"issues":[{"id":139989,"project":{"id":215,"name":"Book Meeting Room
Error status is 0.
Different to standard JSON, JSONP responses should be wrapped in a function call.
Instead of:
{"issues":[{"id":139989,"project":{"id":215,"name":"Book Meeting Room...
You should be getting something like the following from the server:
handler({"issues":[{"id":139989,"project":{"id":215,"name":"Book Meeting Room"}}]});
I ran into a similar issue and found that passing the callback or jsonp parameter with a handler name solved it. More info here in the redmine documentation.
In jQuery this would be my request:
$.get('someurl', {'callback': 'foo'}, function (data, status, xhr) {
... request logic ...
}, 'jsonp'
);
...and this would be your request with the callback parameter:
$http({
method: 'JSONP',
url: url,
callback: 'something'
}).
success(function(data, status) {
console.log(data);
}).
error(function(data, status) {
console.log("Error "+status);
});
This may not help you with the authentication woes but will hopefully get you past this error.

How do I catch a 401 for a partial that I can't access?

In my app I have a token mechanism for authentication.
Every API call needs the token, otherwise it returns a 401.
Which I can easily handle with a response interceptor.
Now when I am using regular routes, and say the token expire, and I try to visit a partial that requires authentication, How will I trap 401 that I get while routing ?
In cases where the first thing that the page comes is making an API call, I will come to know of token expiry and will logout the user.
I want to be able to stop the user from visiting a view if the token has expired.
Will response interceptors take care of this scenario also ?
In case you want to do special processing specific to a partial, you can create a resolve function to check for the defined partial and take appropriate action. It would look something like:
function CheckTemplate() {
return {
"TemplateCheck": function ($route, $http) {
var url = $route.current.templateUrl;
$http.get(url)
.error(function(data, status, headers, config) {
if (status===404) {
... // Do what you need to do
}
})
}
}
}
Here is a sample plunker checking for a 404 on a partial:
http://plnkr.co/edit/4tagMIlcH0jC1A0YODRt?p=preview

Categories

Resources