I am trying to log in a user from a web site. I am using parse-server hosted at Microsoft Azure. I keep getting the following error, just trying to access the home page:
Error handling request: ParseError { code: 209, message: 'invalid session token' } code=209, message=invalid session token
And the browser throws a "...redirected you too many times." error. I'm not sure what I'm doing wrong, I've tried researching and piecing this together from here: https://github.com/ParsePlatform/parse-server/issues/497 with no luck.
index.js
var express...
etc...
var jsonParser = bodyParser.json();
var urlencodedParser = bodyParser.urlencoded({extended:false});
//Server configuration
...
//Express configuration
var app = express();
app.use(cookieParser()); // read cookies (needed for auth)
// get information from html forms
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(bodyParser.json());
// app.set('port', process.env.PORT || 3000);
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');
app.use('/public', express.static(__dirname + '/public'));
app.use('/parse', new ParseServer(config.server));
app.use('/parse-dashboard', ParseDashboard(config.dashboard, true));
app.use(cookieSession({
name: "COOKIE_NAME",
secret: "COOKIE_SECRET",
maxAge: 15724800000
}));
app.use(function (req, res, next) {
Parse.Cloud.httpRequest({
url: 'https://localhost:1337/parse/users/me',
headers: {
'X-Parse-Application-Id': process.env.APP_ID,
'X-Parse-REST-API-Key': process.env.API_KEY,
'X-Parse-Session-Token': req.session.token
}
}).then(function (userData) {
req.user = Parse.Object.fromJSON(userData.data);
next();
}).then(null, function () {
return res.redirect('/login');
});
});
app.use(flash()); // use connect-flash for flash messages stored in session
//routes
require('./routes/routes.js')(app);
app.listen(process.env.PORT || url.parse(config.server.serverURL).port, function () {
console.log(`Parse Server running at ${config.server.serverURL}`);
});
routes.js
// app/routes.js
var bodyParser = require('body-parser');
var jsonParser = bodyParser.json();
var urlencodedParser = bodyParser.urlencoded({extended:false});
module.exports = function(app) {
// HOME PAGE ========
app.get('/', function(req, res) {
res.render('index.ejs', { title: 'Audiomesh' }); // load the index.ejs file
});
// LOGIN ===============================
// show the login form
app.get('/login', function(req, res) {
res.render('login.ejs', { message: req.flash('loginMessage') });
});
app.post('/login', function(req, res) {
Parse.User.logIn(req.body.username, req.body.password).then(function(user) {
req.session.user = user;
req.session.token = user.getSessionToken();
res.redirect('/dashboard');
}, function(error) {
req.session = null;
res.render('login', { flash: error.message });
});
});
// DASHBOARD =====================
app.get('/dashboard', function(req, res) {
res.render('dashboard.ejs', {
user : req.user // get the user out of session and pass to template
});
});
// LOGOUT ==============================
app.get('/logout', function(req, res) {
req.logout();
res.redirect('/');
});
};
login.ejs
<body>
<p><%= message %></p>
<form name="loginForm" action="/login" method="post">
<label>Email</label>
<input type="email" name="email"></input>
<label>Password</label>
<input name="password" type="password"></input>
<input class="button" type="submit" value="Log In">
</form>
<p>Coming soon azure</p>
<p>Back to home page</p>
</body>
The goal of my web site is for the home page to be an advertising/landing page for the mobile app. So if you're logged in, there's no evidence here. Once you click "Login" then it would check if the user is logged in and either load their dashboard (if true), or the login page (if false).
The problem right now is I can't even load the home page. I get too many redirects.
Related
I am learning passport.js and session, and am trying to add a local login feature to my website.
What I was trying to do is as follows:
Secret page: When users are authenticated, they can access to the secret page, otherwise they will be transfered to the login page.
Login page: If the username and password match, users are authenticated and are transfered to the secret page, otherwise they would be transfered back to the login page.
Register page: Users provide username and password, a new MongoDB document is created and stored in my database, meanwhile, the user is authenticated in this session and are transfered to the secret page.
My Problem:
Login page works fine: The authentication process in the login page works perfectly fine. When logined, a cookie is sent to the browser, the user is authenticated in this session and is successfully accessed to the secret page.
Register page data insert works fine: After register, the new password and username is successfully saved in the MongoDB database. User could login with this newly registered username.
Register page authentication failed: The register page, although using the same passport.authenticate() function, failed in the authentication process. I didn't get any error messages on my console, either.
I searched on Google and tried several methods of passport authentication, and they all worked very well on the 'login' POST Request, but failed on the 'register' POST Request.
I have read the documentation of passport-local and passport-local-mongoose. I have also tried this solution. But they all failed in the authentication process in the register page.
I use express-session, passport, passport-local-mongoose packages.
I'm wondering if my understanding of passport authentication is still lacking?
Thank you so much for your help and patience!
My Code:
EJS File - Register Page:
<!-- ... -->
<form action="/register" method="POST">
<div class="form-group">
<label for="email">Email</label>
<input type="email" class="form-control" name="username">
</div>
<div class="form-group">
<label for="password">Password</label>
<input type="password" class="form-control" name="password">
</div>
<button type="submit" class="btn btn-dark">Register</button>
</form>
<!-- ... -->
JS File:
require('dotenv').config();
const express = require('express');
const app = express();
const port = 3000;
const ejs = require('ejs');
const session = require('express-session');
const passport = require('passport');
const passportLocalMongoose = require('passport-local-mongoose')
app.use(express.urlencoded({
extended: true
}));
app.use(express.static("public"));
app.set("view engine", "ejs");
//session and passport set up
app.use(session({
secret: process.env.SECRET,
resave: false,
saveUninitialized: true,
cookie: {
sameSite: 'lax'
},
}))
app.use(passport.initialize());
app.use(passport.session());
//user database set up ////////
const mongoose = require("mongoose");
main().catch(err => console.log(err));
async function main() {
await mongoose.connect('mongodb://localhost:27017/userDB');
}
const userSchema = new mongoose.Schema({
username: {
type: String,
unique: true
},
password: String
})
userSchema.plugin(passportLocalMongoose)
const User = mongoose.model("User", userSchema)
passport.use(User.createStrategy());
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());
//user database set up end ///////
//GET Request
app.get("/", function(req, res) {
res.render("home");
})
app.get("/login", function(req, res) {
res.render("login");
})
app.get("/register", function(req, res) {
res.render("register");
})
//Secret Page ////////////////////////////////
app.get("/secrets", function(req, res) {
if (req.isAuthenticated()) {
res.render("secrets")
} else(
res.redirect("/login")
)
})
app.get('/logout', function(req, res) {
req.logout(function(err) {
if (err) {
console.log(err);
}
res.redirect('/');
});
});
//POST request
//Register POST Request ////////////////////////////////
app.post("/register", function(req, res) {
User.register(new User({
username: req.body.username
}), req.body.password,
function(err, user) {
if (err) {
console.log(err);
res.redirect('/register')
}
passport.authenticate('local'), function(req, res) {
res.redirect("/secrets");
}
}
)
})
app.post('/login', passport.authenticate('local', {
failureRedirect: '/login',
}), function(req, res) {
res.redirect("/secrets");
});
app.listen(port, function() {
console.log("start listening to port 3000")
})
I tried this answer by adding a parameter 'returnCode' to the call back of the passport authenticate function. Although the return code logged is 'undefined', the code successfully worked! I still don't know precisely why it worked simply by adding a parameter, but I think that's due to my lack of understanding of passport?
One thing I found very unhelpful is that the example page on the passport-local documentation is 404 not found. I wonder if there are any helpful examples I could find to study passport-local?
Here's my Code
app.post("/register", function(req, res) {
User.register(new User({
username: req.body.username
}), req.body.password,
function(err, user) {
if (err) {
console.log(err);
res.redirect('/register')
} else {
passport.authenticate('local', {})(req, res, function(returnCode) {
console.log(returnCode); //return: undefined
res.redirect('/secrets');
})
}
}
)
})
I've recently started learning on my own and I am stuck at this and can't get past it.
I'm trying to create a login page and for the first time I'm using middleware
I'm getting an error: throw new TypeError('app.use() requires a middleware function')
TypeError: app.use() requires a middleware function
This is the code down below:
var express = require("express"),
mongoose = require("mongoose"),
passport = require("passport"),
bodyParser = require("body-parser"),
User =require("./models/user"),
LocalStrategy =require("passport-local"),
passportLocalMongoose = require("passport-local-mongoose");
mongoose.connect("mongodb://localhost:27017/auth_demo_app", { useUnifiedTopology: true },{ useNewUrlParser: true });
var app = express();
app.set('view engine', 'ejs');
app.use(bodyParser.urlencoded({extended:true}));
app.use(require("express-session")({
secret: "Neno is the best and cutest dog in the world.",
resave: false,
saveUninitialized: false
}));
app.use(new LocalStrategy(User.authenticate()));
app.use(passport.initialize());
app.use(passport.session());
passport.serializeUser(User.serializeUser()); // Encoding the session
passport.deserializeUser(User.deserializeUser()); // Decoding the session
// =========
// ROUTES
// =========
app.get("/", function(req, res){
res.render("home");
});
app.get("/secret", function(req, res){
res.render("secret");
});
// ===========
// Auth ROUTES
// ===========
// Show Signup Form
app.get("/register", function (req, res){ // req - request / res - response
res.render("register");
});
//handling USER SIGN UP
app.post("/register", function(req, res){
req.body.username
req.body.password
User.register(new User({username: req.body.username}), req.body.password, function(err, user){
if(err) {
console.log(err);
res.render("register");
} else {
passport.authenticate("local")(req, res, function(){
res.redirect("secret");
})
}
});
})
//handling USER LOG IN / LOGIN ROUTES
app.get("/login", function (req, res){
res.render("login");
});
//login logic
//middleware
app.post("/login", passport.authenticate("local", {
successRedirect: "/secret",
failureRedirect: "/login"
}),function(req, res) {
});
app.listen(3000, function (){
console.log("Server Started......");
})
You need to pass strategy to passport, not to the app.
Replace
app.use(new LocalStrategy(User.authenticate()));
With
passport.use(new LocalStrategy(User.authenticate()));
Also I think you need to pass a function new LocalStrategy(User.authenticate) instead of it's result. Unless of course you have implemented it to return a callback (hard to say w/o seeing your code)
I'm learing ExpressJS, i want to do the login part , but i gave me this
Cannot POST /login
im using the post method why it gave me this error
here a detailed post , thank you in advance for helping me
html part
<form method="POST">
<div class="container">
<label for="uname"><b>Username</b></label>
<input type="text" placeholder="Enter Username" name="name" >
<label for="psw"><b>Password</b></label>
<input type="password" placeholder="Enter Password" name="password">
<button type="submit">Login</button>
</div>
</form>
The route.js
router.post('/login'),(req,res)=>{
var username= req.body.name;
var password = req.body.password;
con.query('SELECT * FROM authentication WHERE username = ?',username, function (error, results, fields) {
if (error) {
// console.log("error ocurred",error);
res.send({
"code":400,
"failed":"error ocurred"
})
}else{
// console.log('The solution is: ', results);
if(results.length >0){
if(results[0].password == password){
res.send({
"code":200,
"success":"login sucessfull"
});
}
else{
res.send({
"code":204,
"success":"username and password does not match"
});
}
}
else{
res.send({
"code":204,
"success":"username does not exits"
});
}
}
});
}
module.exports = router
index.js
const express = require('express');
const app = express()
const bodyParser = require("body-parser");
const indexRouter = require('./routes/route')
const con = require('./models/db')
con.connect(function(err) {
if (err) {
return console.error('error: ' + err.message);
}
console.log('Connected to the MySQL server.');
});
app.use(bodyParser.urlencoded({
extended: false
}));
app.use(bodyParser.json());
var exphbs = require('express-handlebars');
console.log(__dirname)
app.use('/',express.static(__dirname + '/public'));
app.engine('handlebars', exphbs());
app.set('view engine', 'handlebars');
app.use('/',indexRouter)
const PORT = 5000;
app.listen(PORT,()=>console.log('it started on 5000'))
when trying to post this form i'm getting:
Cannot POST /login
what am i missing here?
You should handle current page, not '/login' page in route.js :
router.post('/', //...
Instead of writing
router.post('/login', //...
Because you sent the form data to the current page not to the '/login' page
Why current page ?
Because, you didn't define action attribute in your form
You need to define form action
<form action="/login" method="post">
But I recommend you to use js for sending requests
fetch('/login', {
method: 'POST',
body: JSON.stringify(yourFormData),
// ...another Opts if it needs
})
Also it can be problem with your server code because I don't see defining router in indexRouter file, you should add it:
const express = require('express');
const router = express.Router();
// then your code:
router.post('/login', loginController);
But you can add this line for check post requests:
app.post('/login', (req, res) => {
res.status(201).json(req.body); // or console.log
});
I'm calling an express endpoint from after form submission in Jquery. So when the form submits, it calls signUpUser(value) which then initiates an ajax request to the express server.
The call to /signup is resulting in a 404, I thought I was setting up the endpoint properly.
Any reason it is giving a 404? I've tried GET/POST and a few other iterations.
$(document).ready(function(){
$('#signupForm').submit(function() {
console.log("here");
console.log("yup");
var value=$("#email").val();
signUpUser(value);
});
var signUpUser = function (value){
console.log("yaaa");
$.ajax({
type:"GET",
url:"/signup"
})
.done(function(){
window.location='/confirmation.html';
})
.fail(function(){
alert('An error occurred while trying to sign up. Please try again.')
});
};
});
var express = require('express');
var app = express();
var cors = require('cors');
var path = require('path');
var bodyParser = require('body-parser');
var http = require('http');
var fs = require('fs');
app.set('port', (process.env.PORT || 5000));
app.use(express.static(__dirname + '/public'));
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(cors());
var router = express.Router();
app.get('/', function(req, res) {
res.sendFile(path.join(__dirname + '/index.html'));
});
app.get('/thesis.html', function(req, res) {
res.sendFile(path.join(__dirname + '/thesis.html'));
});
app.get('/confirmation.html', function(req, res) {
res.sendFile(path.join(__dirname + '/confirmation.html'));
});
app.get('/about.html', function(req, res) {
res.sendFile(path.join(__dirname + '/about.html'));
});
app.post('/signup', function (req, res) {
$.ajax({
type:"POST",
url:"https://us11.api.mailchimp.com/3.0/lists/8085fb931b/members",
user: 'anystring:XX',
header: 'content-type: application/x-www-form-urlencoded',
data: { "email_address": "ttttt#ssssssss.com",
"status": "subscribed"
}
})
.done(function(){
window.location='/confirmation.html';
res.send(200);
})
.fail(function(){
alert('An error occurred while trying to sign up. Please try again.')
});
});
<form id="signupForm" ng-controller="formController">
<fieldset>
<input type="test" id="email" name="field1" id="field1" ng-model="email">
<input type="submit" value="Create Profile">
</fieldset>
</form>
The end point you're trying to hit, /signup, is a declared as a POST end point. The type attribute in your ajax request is GET. You're getting a 404 because you're trying to make a request to a GET end point that doesn't exist.
I've tried to get csurf to work but seem to have stumbled upon something. The code so far looks like this:
index.ejs
<form method="post" action="/">
<input type="hidden" name="_csrf" value="{{csrfToken}}">
.
.
</form>
Where you insert password and username in the form.
app.js
var express = require('express');
var helmet = require('helmet');
var csrf = require('csurf');
var path = require('path');
var favicon = require('serve-favicon');
var flash = require('connect-flash');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var session = require('express-session');
var routes = require('./routes/index');
var users = require('./routes/users');
var profile = require('./routes/profile');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
//Security shyts
app.use(helmet());
app.use(helmet.xssFilter({ setOnOldIE: true }));
app.use(helmet.frameguard('deny'));
app.use(helmet.hsts({maxAge: 7776000000, includeSubdomains: true}));
app.use(helmet.hidePoweredBy());
app.use(helmet.ieNoOpen());
app.use(helmet.noSniff());
app.use(helmet.noCache());
// rest of USE
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(session({secret: 'anystringoftext', saveUninitialized: true, resave: true, httpOnly: true, secure: true}));
app.use(csrf()); // Security, has to be after cookie and session.
app.use(flash());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', routes);
app.use('/users', users);
app.use('/profile', profile);
// catch 404 and forward to error handler
app.use(function (req, res, next) {
res.cookie('XSRF-TOKEN', req.csrfToken());
res.locals.csrftoken = req.csrfToken();
next();
})
//app.use(function(req, res, next) {
// var err = new Error('Not Found');
// err.status = 404;
// next(err);
//});
// error handlers
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
module.exports = app;
Where I've put csrf after session and cookie parser.
index.js
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'some title',message: '' });
});
router.post('/',function(req,res){
// Where I have a bunch of mysql queries to check passwords and usernames where as if they succeed they get:
res.redirect('profile');
// Else:
res.redirect('/');
});
What I get after submiting the form, no matter if I insert the correct username and password or not I still get the same error:
invalid csrf token
403
ForbiddenError: invalid csrf token
Also I want add that I've been working with node for about 2 weeks, so there is still alot I need to learn probably.
{{csrfToken}} isn't an EJS construction, so it's not expanded at all and is probably sent literally to your server.
This should work better:
<input type="hidden" name="_csrf" value="<%= csrfToken %>">
The middleware is setting csrftoken though, with lowercase 't', where the template expects an uppercase 'T':
res.locals.csrftoken = req.csrfToken(); // change to `res.locals.csrfToken`
You also generate two different tokens, which is probably not what you want. Store the token in a variable and reuse that:
app.use(function (req, res, next) {
var token = req.csrfToken();
res.cookie('XSRF-TOKEN', token);
res.locals.csrfToken = token;
next();
});
And lastly, you probably have to move your middleware to before the route declarations, otherwise it won't be called:
app.use(function (req, res, next) {
var token = req.csrfToken();
res.cookie('XSRF-TOKEN', token);
res.locals.csrfToken = token;
next();
});
app.use('/', routes);
app.use('/users', users);
app.use('/profile', profile);
My Express version is 6.14.4. The most important matter is you have to maintain the order of the line.
App.js
var cookieParser = require('cookie-parser');
var csrf = require('csurf');
var bodyParser = require('body-parser');
//order of bellow lins is very important
app.use(bodyParser.urlencoded({ extended: false }))
app.use(cookieParser())
app.use(csrf({ cookie: true }))
routes/index.js
var express = require('express');
var router = express.Router();
router.get('/user/signup', function(req, res, next){
console.log("csruf: "+req.csrfToken());
res.render('user/signup', { csrfToken: req.csrfToken() });
});
router.post('/postuser', function(req, res, next){
//res.render('/');
res.redirect('/');
});
view file
<form action="/postuser" method="POST">
<div class="form-group">
<label for="email"> E-Mail</label>
<input type="text" id="email" name="email" class="form-control">
</div>
<div class="form-group">
<label for="password">Password</label>
<input type="password" id="password" name="password" class="form-control">
</div>
<input type="hidden" name="_csrf" value="{{csrfToken}}">
<button type="submit" class="btn btn-primary">Sign Up</button>
</form>