Express js Redirect not rendering page - express

I am trying to redirect the user that uses my website after he has logged into his account, he will be redirected to a dashboard.
The problem is that I can see a request for the /dashboard route in the Network tab of the browser Inspection Tools, but the page never loads.
This is my code so far.
router.post('/login', function(request, response){
// verify against database and send back response
var userData = {};
userData.email = request.body.email;
userData.password = request.body.password;
userData.rememberPassword = request.body.rememberPassword;
// check if in the database and re-route
var query = database.query('SELECT * FROM users WHERE email = ?', [userData.email], function(error, result){
if(error){
console.log('Error ', error);
}
if(result.length){
// check if the password is correct
if(userData.password === result[0].password){
// redirect to the dashboard
// TODO this piece of code does not redirect correctly
response.redirect('/dashboard'); // < HERE
console.log('Haha');
}
}
else{
// do something when there is are no results
// invalid email status code
response.statusCode = 405;
response.send('');
}
});
});
And this is the route towards the dashboard, and it is being rendered properly when accessed in the browser.
router.get('/dashboard', function(request, response){
response.render(path.resolve(__dirname, 'views', 'dashboard.pug'));
});
Why can't it redirect when the user completes the login process?
Thanks.

The issue can be in the frontend and not in the backend. If you are using AJAX to send the POST request, it is specifically designed to not change your url.
Use window.location.href after AJAX's request has completed to update the URL with the desired path.But the easiest way would be to create a form with action as /login and use the submission to trigger the url change.
To make sure that the problem does not lie with the backend,
Add a logging statement to router.get('/dashboard' to verify if
the control was passed.
Check that the HTTP status code of the /login route is 302 indicating a redirect and location header has the route /dashboard.
Content type of response /dashboard is text/html.If not please set it using res.setHeader("Content-Type", "text/html").

Related

Lambda#edge redirect gets in a redirect loop

I have a static website on aws s3. Have setup route 53 and cloud front and everything works smoothly. s3 Bucket is setup to serve index.html as index document.
Now I have added another file called index-en.html that should be served when the request country is any other country and not my home country.
For this I have added a lambda#edge function with the following code:
'use strict';
/* This is an origin request function */
exports.handler = (event, context, callback) => {
const request = event.Records[0].cf.request;
const headers = request.headers;
/*
* Based on the value of the CloudFront-Viewer-Country header, generate an
* HTTP status code 302 (Redirect) response, and return a country-specific
* URL in the Location header.
* NOTE: 1. You must configure your distribution to cache based on the
* CloudFront-Viewer-Country header. For more information, see
* http://docs.aws.amazon.com/console/cloudfront/cache-on-selected-headers
* 2. CloudFront adds the CloudFront-Viewer-Country header after the viewer
* request event. To use this example, you must create a trigger for the
* origin request event.
*/
let url = 'prochoice.com.tr';
if (headers['cloudfront-viewer-country']) {
const countryCode = headers['cloudfront-viewer-country'][0].value;
if (countryCode === 'TR') {
url = 'prochoice.com.tr';
} else {
url = 'prochoice.com.tr/index-en.html';
}
}
const response = {
status: '302',
statusDescription: 'Found',
headers: {
location: [{
key: 'Location',
value: url,
}],
},
};
callback(null, response);
};
I have also edited cloud front behavior to whitelist Origin and Viewer-country headers and setup the cloudfront Viewer-Request event and lambda Function ARN relation.
However I get a "too many redirect error".
I have 2 questions:
How to correct the "too many redirects error"?
For viewers outside "TR" the default landing page should be index-en.html, from which 2 more pages in english are accessible via navigation menu. So when users request a specific page from page navigation they should be able to access those pages, when no page is requested the default landing page should be served.
Appreciate help.
Thanks.
You are creating a redirect loop because you are sending the viewer back to the same site, same page, no matter what the results of your test.
if (countryCode === 'TR') {
return callback(null, request);
} else {
...
callback(null,request) tells CloudFront to continue processing the request -- not generate a response. Using return before the callback causes the rest of the trigger code not to run.

How to send Oauth token from callback at the server to the client?

I am using expressJs and passport for authentication. I am using Google Oauth2.0 for login with standard Passport GoogleStrategy. At client I am using axios for sending a login request to the server. My login routes are :
router.get(
"/google",
passport.authenticate("google", { scope: ["profile", "email"] }));
router.get(
"/google/callback",
passport.authenticate("google", { failureRedirect: "/"}),
function(req, res) {
const token = jwt.sign({id: req.user.id}, configAuth.secretKey);
console.log("generated token: ", token);
res.json({success: true, token: 'bearer ' + token});
}
);
I am using the user information from the callback to generate the JWT which I want to sent the client.
At the client I am using axios to send request and get the JWT and store it in localstore.
axios.get('http://localhost:3001/google')
.then((result) => {
console.log("result", result);
localStorage.setItem('jwtToken', result.data.token);
})
.catch((error) => {
// if(error.response.status === 401) {
// this.setState({ message: 'Login failed. Username or password not match' });
// }
console.log("Login error", error);
});
But Axios doesn't wait for the redirect to happen and returns a HTML document with Loading... message. If you try to access the API in the browser, it returns the desired JSON object. Is there a way to wait for redirects. Should I use another library to send login request?
I tried sending the token as url parameter with
res.redirect()
but client and server are at different ports so it doesn't work.
Is there another way to do it?
Google's OAuth2 pathway redirects your browser, resulting in page reloads, a couple of times before it completes. As a result, your client-side code,
axios.get('http://localhost:3001/google')
.then((result) => {
console.log("result", result);
localStorage.setItem('jwtToken', result.data.token);
})...
will never reach the .then() block. You probably see this in the browser; you click a button or something to navigate to 'http://localhost:3001/google', and your localhost:3001 server re-directs your browser to a Google login page. Now that your browser is at the login page, it has no memory of the axios.get statement above--that webpage code is gone.
You need to handle the JWT in client-side code that your server sends in response to
axios.get('http://localhost:3001/google/callback').
This is your browser's final stop in the OAuth2 path--once you get there, you won't be re-directed again. You can put your axios.get function above inside that client-side code.
If you haven't solved the problem, there is a workaround use 'googleTokenStategy' instead of googleOAuth on passportjs. That way you can use react's GoogleLogin plugin to receive the access token from the front end and send it by axios.post to the backend link then set up the jwt. Reference here

Vuejs http request always attach a query parameter

Am using a query param authentication with my backed that requires all http requests have the following
access-token=token
AM using vuejs2 resource
So in my request i want to intercept every request and attach the above so i have
Vue.http.interceptors.push(function (request, next) {
//here add the access token in my url string
//am stuck
next()
});
So i expect when i try
this.$http.get('users')
the request should automatically be
users?access-token=token
Also when ihave
this.$http.get('users?pagination=10')
then request url should have
users?pagination=10&access-token=token
How do i intercept all the requests and attach the query parameter access token
THe way i was able to resolve this was by
if(request.url.indexOf("?") === -1){ //means no access token since nothing is passed to the url
request.url = request.url+"?access-token=token";
}else{
if(request.url.indexOf("access-token") === -1){
request.url = request.url+"&access-token=token"
}
}

Not able to redirect to client side with token from server(express) side route

I am using 'googleapis' npm package to do token based google authentication.
I am redirected to '/api/auth/success/google' route inside express after google provided authentication and redirects us to the uri stated in google app credentials.
The problem I am facing is that ,I have retrieved the tokens on server side,but I am unable to send those tokens to client side for them to be saved in cookies.
The problem I am facing is because,'/api/auth/success/google' is redirected from google side and not an ajax call from client side.So if I send the tokens back in res,where will it redirect.Also please suggest a way to redirect from server side to client side,along with access_token.
server side code.
//Route reached after google successful login/authentication
app.get('/api/auth/success/google',function(req,res){
console.log("inside redirect");
var code = req.query.code;
oauth2Client.getToken(code, function(err, tokens) {
// Now tokens contains an access_token and an optional refresh_token. Save them.
if(!err) {
oauth2Client.setCredentials(tokens);
}
res.sendFile('./index.html');
});
})
Client side call
//Google login requested from this function
googleLogin(){
event.preventDefault();
$.ajax({
type : 'POST',
url : baseURL + 'api/authenticate/google',
success: (function(data) {
if (data.redirect) {
document.location.href = data.redirect;
}
}).bind(this)
});
}
//Route handling request of google access
app.post('/api/authenticate/google',function(req,res){
// generate a url that asks permissions for Google+ and Google Calendar scopes
var scopes = [
googlecredentials.SCOPE[0],
googlecredentials.SCOPE[1]
];
var url = oauth2Client.generateAuthUrl({
access_type: 'offline', // 'online' (default) or 'offline' (gets refresh_token)
scope: scopes // If you only need one scope you can pass it as string
});
res.send({ redirect: url });
})
//Google App Credentials
var OAuth2 = google.auth.OAuth2;
var oauth2Client = new OAuth2(googlecredentials.CLIENT_ID, googlecredentials.CLIENT_SECRET, googlecredentials.REDIRECT_URL);
googlecredentials.CLIENT_ID - 858093863410-j9ma1i7lgapupip1ckegc61plrlledtq.apps.googleusercontent.com
REDIRECT_URL - http://localhost:3000/api/auth/success/google where localhost:3000 runs server side
If you send the redirect URL back in the res, the client-side should be able to check for the presence of the redirect URL in the response, and if it exists, push your user to that URL.

Backbone.js and user authentication

I have been wondering for quite a while how I would go about authenticating users using Backbone because I have been reading a few articles about it and a lot of them are talking about tokens and keys.. But I just want to be able to sign in a user and register a user like you would normally.
I was thinking that on the web app start up there would be a request to the route '/me' and then the server gives the user back appropriate information if he/she is logged in.
Like if the route came back with {loggedIn: false} the backbone router would send the user to the login/register pages only. But if it came back with a users profile information then it would obviously mean he had a session.
Is this an okay way of going back user authentication when using Backbone?
Short answer: wire up $.ajax to respond to 401 (Unauthorized) status codes.
Long answer: We're consuming a RESTful api from a single page website. when the server detects an unauthorized request, it just returns a 401. The client will redirect to /login?#requested/resource.
/login will prompt for authorization (redirect to google's oath server in our case) then add an authorization cookie and redirect to the originally requested #requested/resource
we're also sending the auth cookie on every $.ajax request.
Hopefully this is helpful.
define(
[
'jquery',
'jquery.cookie'
],
function ($) {
var redirectToLogin = function () {
var locationhref = "/login";
if (location.hash && location.hash.length > 0) {
locationhref += "?hash=" + location.hash.substring(1);
}
location.href = locationhref;
};
var $doc = $(document);
$doc.ajaxSend(function (event, xhr) {
var authToken = $.cookie('access_token');
if (authToken) {
xhr.setRequestHeader("Authorization", "Bearer " + authToken);
}
});
$doc.ajaxError(function (event, xhr) {
if (xhr.status == 401)
redirectToLogin();
});
});