Hey so I am try to use express-session
and connect-mongodb-session
, TypeScript Express/Node Api now what I want to do is when a user is logged I will be using express-session to make that cookie and automatically that cookie is persisted to MongoDB. Now the problem that I am having is I want to add detail to that session i.e the user's info so that when persisting the user I know their username etc...
Now when not using TypeScript I can simply do something like this to add user detail to session being instatiated:
request.session.user = {username:'John', id='97y9797977c9q7dw7y9qw7d9721'}
But now when using TypeScript I get hit by the following error when I try to do the same as above:\
Code Below: This is my setup for express-session
and connect-mongodb-session
const store = MongoStore(expressSession);
const mongoURI = process.env.mongoURI;
const mongoStore = new store({
collection: 'usersessions',
uri: mongoURI,
expires: 10 * 60 * 60 * 24 * 1000
});
app.use(
expressSession({
name: '_sid',
secret: process.env.session_secret,
resave: false,
saveUninitialized: false,
store: mongoStore,
cookie: {
httpOnly: true,
maxAge: 10 * 60 * 60 * 24 * 1000,
secure: process.env.NODE_ENV === 'production'
}
})
);
Code below is my SignIn method controller
SignIn(request: Request, response: Response) {
const form = new Formidable.IncomingForm();
try {
form.parse(request, async (error, fields, files) => {
if (error) {
return response.status(500).json({
msg: 'Network Error: Please try again later'
});
}
const { username, password } = fields;
if (!username || !password) {
return response.status(400).json({ msg: 'All fields are required' });
}
const user: any = await userModel.findOne({
usernam: username
});
if (!user) {
return response.status(404).json({
msg: 'Account with this username does not exist'
});
}
const hashedPassword = user.password;
const isPasswordValid = await Bcrypt.compare(password, hashedPassword);
if (!isPasswordValid) {
return response.status(400).json({ msg: 'Invalid credentials' });
}
const isUserSessionExisting = await userSession.findOne({
'session.user.username': username
});
if (isUserSessionExisting) {
return response
.status(200)
.json({ msg: 'Account already logged in' });
}
const userSessionObj = {
username: user.username,
id: user._id
};
request.session.user = userSessionObj; //This is where the error is coming
return response.status(200).send(request.sessionID);
});
} catch (error) {
return response
.status(500)
.json({ msg: 'Network Error: Please try again later' });
}
}
How can I resolve this issue
you have 2 ways to declare session.
import {Request} from "express"
type Req= Request & { session: Express.Session }; // this will be merges
or
declare global {
namespace Express {
interface Request {
// currentUser might not be defined if it is not logged in
session: Express.Session;
}
}
}
and this is Session interface:
interface Session extends SessionData {
id: string;
regenerate(callback: (err: any) => void): void;
destroy(callback: (err: any) => void): void;
reload(callback: (err: any) => void): void;
save(callback: (err: any) => void): void;
touch(): void;
cookie: SessionCookie;
}
as you can see there is no user property. Because usually we store a unique identifier in the cookie which is database id. Because user name can be changed in the future but user's database id or if you are doing google oauth authentication, user's google id dont change. Storing id would be enough. But if you still wanna attach user object to the session, create a new User interface
interface User{
username: string;
id:string
}
type NewSession=Express.Session & User
declare global {
namespace Express {
interface Request {
// currentUser might not be defined if it is not logged in
session: NewSession;
}
}
}