I was working on a project that have a separate frontend and backend. I use tsoa-express and express session for my authentication(port 4040) and I create a simple frontend(port 5500) for testing.
Backend:
// Session.ts
class Session {
public mount(_express: Application): Application {
_express.set('trust proxy', 1)
const sess: SessionOptions = {
secret: Locals.config().appSecret,
resave: false,
saveUninitialized: true,
// rolling: true,
proxy:true,
cookie: {
maxAge: 3600 * 1000, // 1 hr
httpOnly: false,
secure: false,
domain: undefined,
sameSite: false,
}, // cookie expire in half an hour from last activity
store: MongoStore.create({
mongoUrl: Locals.config().mongooseUrl
})
};
_express.use(session(sess));
return _express;
}
}
// authController.ts
@Tags("Authentication")
@Route("auth")
export class AuthController extends Controller {
@Post("/login")
@Middlewares([AuthService.login])
public async login(@Body() body: loginInput): Promise<any> {
return null;
}
}
// authService.ts
export class AuthService {
public async login(req: express.Request, res: express.Response, next: express.NextFunction) : Promise<void> {
res.header('Access-Control-Allow-Credentials', "true");
res.header('Access-Control-Allow-Origin', req.headers.origin);
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
res.header('Access-Control-Allow-Headers', 'X-Requested-With, X-HTTP-Method-Override, Content-Type, Accept');
if (req.body.hasOwnProperty("username") && req.body.hasOwnProperty("password")) {
const user = await User.findOne({login_name: req.body.username});
if (user) {
if (bcrypt.compareSync(req.body.password, user.password)){
if (!req.session.isAuthenticated){
req.session.regenerate(function (err: any) {
if (err) throw next(err);
req.session.isAuthenticated = true;
req.session.user_id = user._id;
req.session.session_users = 1;
req.session.save(function (err) {if (err) return next(err)})
});
res.status(200).send({user: user._id, sid: signature.sign(req.sessionID, Locals.config().appSecret)});
} else {
req.session.session_users = (req.session.session_users) ? req.session.session_users++ : 1;
res.status(200).send({user: user._id});
}
} else {
res.status(401).send({ reason: "Failed to login.", details: "Invalid password. Please try again." });
}
} else {
res.status(401).send( { reason: "Failed to login.",details: "Invalid username. Please try again." });
}
} else {
next()
}
}
}
Frontend html:
<!DOCTYPE html>
<html lang="en">
<head>
</head>
<button id="login-btn">Login button</button>
<script src="script.js"></script>
</html>
Frontend JS:
const login_button = document.getElementById('login-btn');
const data = {
"username": "any valid username",
"password": "any valid pw"
}
login_button.addEventListener('click', async _ => {
fetch('http://localhost:4040/auth/login', {
method: 'post',
mode: 'cors',
cache: 'default',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify(data)
})
.then(response => response.json())
.then(data => {
console.log(data);
window.localStorage.setItem('sid', data['sid']);
})
.catch(error => {
console.error(`Error: ${error}`);
});
});
After I use the login function, My browser get the cookie but it failed to authenticate in the following requests. My login function failed to increase the session_user value and all variables value in req.session is undefined. I am forced to use express-session for backward compatibility. May I know what is the problem of my code and how should I setup the session so that I can access the values properly?