Logging out with Firebase and Node.JS - node.js

I wanted to provide a Node.JS Express route wrapper for users who needed to logout and didn't have JavaScript enabled on the front-end. DB is my reference to my Firebase:
router.get('/logout', function(req, res) {
DB.unauth();
res.redirect(302, '/');
});
When I try to logout this way having been logged in, I get the following error:
Error: Can't set headers after they are sent.
The documentation for Firebase.unauth() is pretty light, but calling it in a route (with or without the res.redirect) causes the error. Does anyone have a suggestion or workaround for this issue?

So i was running into the same problem. For me it was that i was using the asynchronous authDataCallback function.
Apparently onAuth sets your headers so when you try to go to /logout your headers are set and the redirect will fail. So what i did is i switch the authDataCallback
that i had checking for login states to:
var authData = ref.getAuth();
if (authData) {
console.log("User " + authData.uid + " is logged in with " + + authData.provider);
} else {
console.log("User is logged out");
}
then my route for log out work flawlessly.
app.get('/logout', function(req , res){
ref.unauth();
res.redirect('/');
});

Looks like that error is being thrown on the redirect - you can't headers once the body has been sent. Maybe try:
response.writeHead(302, { Location: '/' });
response.end();
If that doesn't work, I'd put money on that .unauth() is actually setting headers, and if it is, you'll probably need to use the ol' <noscript> tag.
All of this said though: you're building an app that uses JavaScript to integrate with Firebase on the back end. Why build a modern web-app that (presumably) relies heavily on JavaScript only to support logging out users when they don't support it? Could they even log in in the first place?

Related

How to send data with redirect back in Express JS

Hello I am new to NodeJs. Currently I am working in node with Express framework.
I installed the express-back package in my project and now I want to send send back data to view from where post request fired.
Below is my code that I write:
routes.js
router.post('/register/user',Rules.UserRules.registerUser,UserController.registerUser)
UserController.js
const {check, validationResult} = require('express-validator');
registerUser = function (req, res, next) {
// Validate request parameters, queries using express-validator
const errors = validationResult(req)
console.log("==== errors ===")
console.log(errors.array())
if (!errors.isEmpty()) {
console.log("==== erorror founded ====")
return res.redirect('/signup',{errors:errors})
}else{
console.log('--- form body ----')
console.log(req.body)
}
}
module.exports = {registerUser}
When I submit my form to this route then control moves to UserController and I validations fails then I want to send it back to view without defining the redirect path I just want to send it back to view from where request received with errors. But I did not find any useful solution yet.
Is there any idea that how I can achieve this target. Suggest any useful link for nodejs beginner.
use res.send(errors) it send errors to client at this route. but if you want to redirect it to another route and then send it to client you have to create /signup route and use res.send(errors) it send errors to client. by default ``` res```` will redirect to redirected route.
router.post('/signup', (req, res)=>{
//send error or do somethings.
res.json(req.body.errors);
})
Use
app.locals.errors=errors
to make your error variable available to your template upon redirection as a general guide. Read more at http://expressjs.com/en/5x/api.html#app.locals. Remember, this will share the error variable across the application, so do not forget to apply logic that allows only the logged in user to view the error information relevant to that user.

Passport-auth0 - infinite redirect loop, "Invalid authorization request state."

I'm trying to get a basic Auth0 app running. I followed the Node example on the Auth0 dashboard but I ran into an infinite redirect loop between /login and /callback. I tried to simplify the code using the getting started example of this repo's readme, right now my routing code looks like this:
app.get('/login',
passport.authenticate('auth0', {scope: 'openid email profile'}),
(req, res) => res.redirect("/")
)
app.get("/callback",
passport.authenticate('auth0', {failureRedirect: '/login'}),
(req, res) => {
if(!req.user) throw new Error("user null")
res.redirect("/")
}
)
Everything about my setup follows the instructions I got on my Auth0 dashboard.
I did some digging and found out that /login is called twice, then /callback is called twice, then /login twice and so on and so on. I also found out that if I give the /callback's passport.authenticate a callback, it receives these arguments: null, false, {message: "Invalid authorization request state."}
Google didn't find anything meaningful when I searched for the phrase "Invalid authorization request state." and I did everything according to the docs. Any idea what I'm doing wrong?
I have had the same issue with these error and was caused due to session loss on Kubernetes landing my calls to different instances each time (sort of like load balancing), what we did was to lower from 3 instances to 1 and that fixed it. Also you could set in your Auth0Strategy config the value of state: false to double check if this lets you move on.
It turns out I didn't have the /callback route set up properly. This is the proper setup:
router.get("/callback", (req, res, next) => {
passport.authenticate('auth0', (err, user, info) => {
if(err) return next(err)
if(!user) return res.redirect("/failure?info=" + JSON.stringify(info))
req.logIn(user, err => {
if(err) return next(err)
const returnTo = req.session.returnTo
delete req.session.returnTo
res.redirect(returnTo || '/secret')
})
})(req, res, next)
})
res.redirect should lead somewhere else and req.logIn needs to be called with the proper arguments
For those who are still having issues, the problem might lie elsewhere. When I ran into this it turned out to be caused by session cookies that weren't persisting! It turned out my reverse proxy (running on Apache) wasn't configured properly. I've described my solution here: https://stackoverflow.com/a/67891167/8221175
As for why this might happen for those interested, I've posted an explanation on one of the GitHub issues here: https://github.com/auth0/passport-auth0/issues/89#issuecomment-856971807
In short: The state query parameter in the response of a login call is saved in the session. If sessions don't persist, passport can't get that state data and it'll think someone is hijacking your session. That causes the “Invalid authorization request state.” message, as well as the user to be falsy in the passport.authenticate callback. If your code then redirects to '/login', the whole thing repeats, causing an infinite loop.
The fix is to make sure your cookies are saved properly and your sessions therefore persist. You can use the examples I've provided in the links.

res.download() throw Request aborted

I'm using express and trying to download a file, then load the page. I understood that the problem is stopping res.download with res.render but I can' t figure out how to resolve this. I also tried to put res.render() inside the callback function of res.download(), the only thing that happen is that res.render stopped working but the file would download.
app.get("/", function(req, res) {
res.download(
"./public/sample-zip/Lost Sky - Dreams.zip",
"Lost Sky - Dreams.zip",
err => {
if (err) console.log("Errore nel dw: " + err);
}
);
res.render("index");
});
You can't end the same request in multiple ways - download behind the scenes will call sendFile which sends a file to the client and ends the request, similarly render will send page content and also end the request.
The correct approach here is to allow the file to be downloaded to the client and then have the client redirect the page on the back of a successful download.

too many redirects in express

I want to handle all my cookies and session stuff in a function then redirect to the destination path. I use this function in Express:
app.all('*', function(req, res, next){
if('_id' in req.session)
next()
else if('userInfo' in req.cookies){
req.session._id = req.cookies.userInfo._id
next()
} else {
res.redirect('../login')
}
res.end()
})
but browser print this error:
net::ERR_TOO_MANY_REDIRECTS
what's the problem?
This error occurs when a web browser is redirecting you to another web page which then that web page redirects you back to the same browser again. Your configurations are wrong. app.all('*', ..) runs again and again whenever a request is made, which causing repetition.
You need to have better configurations than app.all(*..) //all. You need to specify it more so that it doesn't repeat itself.
I would say limit it down to some urls and not all of them. You could do
app.get('/cookieCheckerPage', function(req, res){
//code here
});
Also please see Error 310 (net::ERR_TOO_MANY_REDIRECTS):

ExpressJS : res.redirect() not working as expected?

I've been struggling for 2 days on this one, googled and stackoverflowed all I could, but I can't work it out.
I'm building a simple node app (+Express + Mongoose) with a login page that redirects to the home page. Here's my server JS code :
app
.get('/', (req, res) => {
console.log("Here we are : root");
return res.sendfile(__dirname + '/index.html');
})
.get('/login', (req, res) => {
console.log("Here we are : '/login'");
return res.sendfile(__dirname + '/login.html');
})
.post('/credentials', (req, res) => {
console.log("Here we are : '/credentials'");
// Some Mongoose / DB validations
return res.redirect('/');
});
The login page makes a POST request to /credentials, where posted data is verified. This works. I can see "Here we are : '/credentials'" in the Node console.
Then comes the issue : the res.redirect doesn't work properly. I know that it does reach the '/' route, because :
I can see "Here we are : root" in the Node console
The index.html page is being sent back to the browser as a reponse, but not displayed in the window.
Chrome inspector shows the POST request response, I CAN see the HTML code being sent to the browser in the inspector, but the URL remains /login and the login page is still being displayed on screen.
(Edit) The redirection is in Mongoose's callback function, it's not synchronous (as NodeJS should be). I have just removed Mongoose validation stuff for clarity.
I have tried adding res.end(), doesn't work
I have tried
req.method = 'get';
res.redirect('/');
and
res.writeHead(302, {location: '/'});
res.end();
Doesn't work
What am I doing wrong? How can I actually leave the '/login' page, redirect the browser to '/' and display the HTML code that it received?
Thanks a million for your help in advance :)
The problem might not lie with the backend, but with the frontend. 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 (in the .done()) to update the URL with the desired path, or use JQuery: $('body').replaceWith(data) when you receive the HTML back from the request.
If you are using an asynchronous request to backend and then redirecting in backend, it will redirect in backend (i.e. it will create a new get request to that URL), but won't change the URL in front end.
To make it work you need to:
use window.location.href = "/url"
change your async request (in front end) to simple anchor tag (<a></a>)
It's almost certain that you are making an async call to check Mongoose but you haven't structured the code so that the redirect only happens after the async call returns a result.
In javascript, the POST would look like something this:
function validateCredentials(user, callback){
// takes whatever you need to validate the visitor as `user`
// uses the `callback` when the results return from Mongoose
}
app.post('/credentials', function(req, res){
console.log("Here was are: '/credentials'";
validateCredentials(userdata, function(err, data){
if (err) {
// handle error and redirect to credentials,
// display an error page, or whatever you want to do here...
}
// if no error, redirect
res.redirect('/');
};
};
You can also see questions like Async call in node.js vs. mongoose for parallel/related problems...
I've been working on implementing nodemailer into my NextJS app with Express. Was having this issue and came across this. I had event.preventDefault() in my function that was firing the form to submit and that was preventing the redirect as well, I took it off and it was redirecting accordingly.
Add the following in your get / route :
res.setHeader("Content-Type", "text/html")
Your browser will render file instead of downloading it

Resources