I'm following a tutorial for Ben Awad and i'm trying to set a userId in an express session after the user logs in to save the cookies in the browser. But when i check the req.session.userId its always undefined.
this is my index.ts
`
const RedisStore = connectRedis(session);
const redis = new Redis({
port: 6379,
host: "127.0.0.1",
});
redis.on("connect", () => console.log("Redis redisClient Connected"));
redis.on("error", (err) => console.log("Redis Client Connection Error", err));
app.use(
session({
name: "SessionID",
store: new RedisStore({
client: redis,
disableTouch: true,
}),
cookie: {
maxAge: 1000 * 60 * 60 * 24 * 365 * 10, //10 years
httpOnly: true,
sameSite: "lax",
domain: _prod_ ? ".codeponder.com" : undefined,
secure: _prod_, // cookie only works in https
},
secret: "adsadafasdasdasfasfdasda",
resave: false,
saveUninitialized: true,
})
);
const apolloServer = new ApolloServer({
schema: await buildSchema({
resolvers: [PostResolver, UserResolver],
validate: false,
}),
context: ({ req, res }): MyContext => ({ em: orm.em, res, req, redis }),
});
await apolloServer.start();
apolloServer.applyMiddleware({
app,
cors: {
credentials: true,
origin: ["http://localhost:3000", "https://studio.apollographql.com"],
},
});
app.listen(4000, () => {
console.log("server started on localhost:4000");
});
};
`
and when i try to save the userId in the login. Here when i log the req.session after assigning it to the user.id i can see it working
`
#Mutation(() => UserResponse)
async login(
#Arg("options") options: UsernamePasswordInput,
#Ctx() { em, req }: MyContext
): Promise<UserResponse> {
const user = await em.findOne(User, { username: options.username });
if (!user) {
return {
errors: [
{
field: "username",
message: "that username doesnt exist",
},
],
};
}
const valid = await argon2.verify(user.password, options.password);
if (!valid) {
return {
errors: [
{
field: "password",
message: "incorrect password",
},
],
};
}
req.session.userId = user.id;
console.log("req.>>", req.session);
req.session.save(() => {
console.log("saved");
});
return { user };
}
}
`
But when i check if the user is logged in or not from this function. req.session.userId is always undefined and not saved in the session
`
#Query(() => User, { nullable: true })
async me(#Ctx() { req, em }: MyContext) {
console.log("req", req.session);
if (!req.session.userId) {
return null;
}
const user = await em.findOne(User, { id: req.session.userId });
return user;
}
`
i tried upgrading/downgrading the packages. Checked my redis connection. Nothing seem to work
Related
I am building a nodejs application
I want to save cookies using nodejs
it send the cookie to the browser
but it does not save on the browser storage
export const signin = async (req, res, next) => {
try {
const user = await User.findOne({
$or: [{ phone: req.body.phone }, { username: req.body.username }],
});
if (!user) return res.status(401).json({ msg: "Wrong Credentials" });
const isCorrect = bcrypt.compareSync(req.body.password, user.password); // true
if (!isCorrect) return res.status(401).json({ msg: "Wrong Credentials" });
const token = jwt.sign({ id: user._id, role: user.role }, process.env.JWT);
const { password, ...others } = user._doc;
res
.cookie("access_token", token, {
httpOnly: false,
secure: false,
maxAge: 60 * 60 * 24 * 7,
})
.status(200)
.json(others);
} catch (error) {
next(error);
}
};
Frontend
const get = path => {
const new_url = `${BASE_URL}${path}`;
return axios.get(new_url || {}, {
withCredentials: true,
credentials: "include",
});
};
I'm following Fullstack React GraphQL TypeScript Tutorial by Ben Awad, but I encountered considerable difficulty during approximately (1:55:00) set up cookies.
I think I connect to Redis successfully, and set express-session, req type, but I'm unable to see my cookies in chrome->applications->cookies.
I try to follow this post, but it's not working-ish for me.
index.ts
const app = express();
app.set("trust proxy", true);
app.set("Access-Control-Allow-Origin", "https://studio.apollographql.com");
app.set("Access-Control-Allow-Credentials", true);
const RedisStore = connectRedis(session)
const redisClient = createClient({ legacyMode: true })
redisClient.connect().catch(console.error)
app.use(
session({
name: 'qid',
store: new RedisStore({
client: redisClient,
disableTouch: true,
}),
cookie: {
maxAge: 1000 * 60 * 60 * 24 * 365 * 10, // 10 year
httpOnly: true,
secure: true, // cookies only works on https if it's true // set to __prod__ by ben awad
sameSite: "none" // csrf
},
saveUninitialized: false,
secret: "izodfg",
resave: false,
})
)
const apolloServer = new ApolloServer({
schema: await buildSchema({
resolvers: [HelloResolver, PostResolver, UserResolver],
validate: false,
}),
context: ({ req, res }): MyContext => ({ em: emFork, req, res })
})
const cors = { // add for apollo studio
credentials: true,
origin: 'https://studio.apollographql.com'
}
await apolloServer.start();
apolloServer.applyMiddleware({ app, cors });
type.ts
export type MyContext = {
em: EntityManager<IDatabaseDriver<Connection>>
req: Request & { session: { userId?: string } }
res: Response
};
./resolvers/user.ts
#Mutation(() => UserResponse)
async login(
#Arg('options') options: UsernamePasswordInput,
#Ctx() { em, req }: MyContext
): Promise<UserResponse> {
const user = await em.findOne(User, { username: options.username });
if (!user) {
return {
errors: [
{
field: "username",
message: "that username doesn't exists",
}
]
}
}
const vaild = await argon2.verify(user.password, options.password);
if (!vaild) {
return {
errors: [
{
field: "password",
message: "incorrect password",
}
]
}
}
req.session.userId = user.id.toString();
return {
user
}
}
Redis Inspect
stored cookie in Redis picture
My nodejs API runs fine for few hours then API does not return data to client. Once I debug I found that TypeOrm Unable to query data from remote postgres server even though postgres server is Connected. Query in Nodejs application die with no error.
I can query data from remote postgres DB from pgAdmin.
The app.ts code
const conn = await createConnection({
host: process.env.TYPEORM_HOST,
password: process.env.TYPEORM_PASSWORD,
type: 'postgres',
username: process.env.TYPEORM_USERNAME,
database: process.env.TYPEORM_DATABASE,
port: Number(TYPEORM_PORT),
logging: TYPEORM_LOGGING === 'true' ? true : false,
synchronize: TYPEORM_SYNCHRONIZE === 'true' ? true : false,
entities: [UserEntity],
});
console.log(conn.options.database);
////#### Middleware Section ####/////
const apolloServer = new ApolloServer({
schema: await CreateSchema(),
subscriptions: {
path: `${ENDPOINT_PATH}`,
},
uploads: false,
//tracing: true,
context: ({ req, res }: any) => ({
req,
res,
...dataLoaderInject,
}),
});
const app = Express();
const whitelist: any = process.env.ENDPOINT_CORS?.split(',').map((x) =>
x.trim()
);
var corsOptions = {
origin: function (origin: any, callback: any) {
if (whitelist.indexOf(origin) !== -1) {
callback(null, true);
} else {
callback(null, false);
}
},
credentials: true,
};
app.use(cors(corsOptions));
app.use(graphqlUploadExpress({ maxFileSize: 500000000, maxFiles: 50 }));
app.use(cookieParser());
apolloServer.applyMiddleware({ app, cors: false, path: ENDPOINT_PATH });
const httpServer = http.createServer(app);
apolloServer.installSubscriptionHandlers(httpServer);
httpServer.listen(ENDPOINT_PORT, () => {
//Register jobScheduler here
JobSchedulerService.sendReminder();
console.log(
`Server started at ${ENDPOINT}:${ENDPOINT_PORT}${ENDPOINT_PATH}`
);
});
POST request where TypeOrm fails to return results from remote postgres server.
app.post('/user', async (req, res) => {
let token = req.cookies.UserCookie;
if (!token) {
console.log('token is not valid ' + token);
return res.send({ ok: false, accessToken: '' });
}
let payload: any;
try {
payload = verify(token, process.env.REFRESH_TOKEN_SECRET!);
} catch (err) {
console.log(err);
return res.send({ ok: false, accessToken: '' });
}
const user = await
getRepository(UserEntity)
.createQueryBuilder()
.where('"ID"=:ID', { ID: payload.userID })
.getOne() // request die here , no error , does not respond anything
.catch( err => {
console.log(err, "User Query error")
})
if (!user) {
console.log('User not found');
return res.send({ ok: false, accessToken: '' });
}
Stack version
Postgres 12
Nodejs : v12.16.3
npm : 6.14.4
"pg": "^8.3.3"
"typeorm": "^0.2.26",
"express": "^4.17.1",
"node-cron": "^2.0.3",
Your response will be much appreciated Thank you.
Platform Used:
NestJs 7.1.2
Postgres
After a certain duration my aws rds session count keeps increasing and the server becomes unresponsive. I need to restart the server again to make it working.
My database connection code in main.ts:
import * as session from 'express-session';
app.use(
session({
store: new (require('connect-pg-simple')(session))({
conString:
'pg://' +
process.env.TYPEORM_USERNAME +
':' +
process.env.TYPEORM_PASSWORD +
'#' +
process.env.TYPEORM_HOST +
'/' +
process.env.TYPEORM_DATABASE,
}),
secret: process.env.COOKIE_SECRET,
resave: false,
saveUninitialized: false,
cookie: { maxAge: 30 * 24 * 60 * 60 * 1000 }, // 30 days
}),
);
app.module.ts code:
TypeOrmModule.forRootAsync({
useFactory: (config: ConfigService) => config.get('database'),
inject: [ConfigService],
})
where my database config is as follows:
import * as path from 'path';
export default {
type: process.env.TYPEORM_CONNECTION,
host: process.env.TYPEORM_HOST,
port: +process.env.TYPEORM_PORT,
username: process.env.TYPEORM_USERNAME,
password: process.env.TYPEORM_PASSWORD,
database: process.env.TYPEORM_DATABASE,
synchronize: true,
dropSchema: false,
logging: false,
retryAttempts: 5,
keepConnectionAlive: true,
entities: [path.join(__dirname, '../') + '**/!(*.d).entity{.ts,.js}'],
migrations: ['migrations/**/*.ts'],
subscribers: ['subscriber/**/*.ts', 'dist/subscriber/**/.js'],
cli: {
entitiesDir: 'src',
migrationsDir: 'migrations',
subscribersDir: 'subscriber',
},
};
Kindly assist...have struggled a lot on this!!
Use the pgPromise connection param instead of the conString param. Also modify apolloServer+express-session configuration settings.
async function main() {
const connection = await createConnection(ormconfig as ConnectionOptions);
const schema = await buildSchema({ resolvers: [DysfunctionalThoughtResolver,UserResolver] });
const server = new ApolloServer({
schema,
context: async ({ req, res }) => ({ req, res }),
playground: {
settings: {
"request.credentials": "same-origin",
}
}
});
var app=express();
var pgSession = require('connect-pg-simple')(session);
app.use(session({
name: process.env.COOKIE_NAME,
saveUninitialized:false,
secret:process.env.COOKIE_SECRET?.split(','),
cookie: {
store: new pgSession({
pgPromise : connection
}),
httpOnly: true,
secure: process.env.NODE_ENV=="prod",
sameSite: true,
maxAge: 600000 // Time is in miliseconds
},
resave: false
}))
await app.listen({port:4000});
server.applyMiddleware({ app });
console.log("Server has started!");
}
main();
Dont forget to add the session table required in connect-pg-simple:
https://github.com/voxpelli/node-connect-pg-simple/blob/HEAD/table.sql
CREATE TABLE "session" (
"sid" varchar NOT NULL COLLATE "default",
"sess" json NOT NULL,
"expire" timestamp(6) NOT NULL
)
WITH (OIDS=FALSE);
ALTER TABLE "session" ADD CONSTRAINT "session_pkey" PRIMARY KEY ("sid") NOT DEFERRABLE INITIALLY IMMEDIATE;
CREATE INDEX "IDX_session_expire" ON "session" ("expire");
TypeORM translation(put in a session.ts file in your models/entities folder).
#Entity()
export class session {
#PrimaryColumn({
type: "varchar",
nullable: false,
//collation:"" //needed?
})
sid:string;
#Column({
type: "json",
nullable: false
})
sess:any;
#Index("IDX_session_expire")
#Column({
type: "timestamp",
precision: 6,
nullable: false
})
expire:Date;
}
Then access it in your resolvers
#Mutation(() => String)
async login(#Args() { email, password }: UserLoginArgs, #Ctx() ctx: any) {
let response = "";
let sess = ctx.req.session;
if (sess.userId) { response = "already logged in"; }
else {
let user = await User.findOne({ where: { email: email } });
if (user) {
let passwordsMatch = await bcrypt.compare(password, user?.password);
if (passwordsMatch) {
sess.userId = user.id;
sess.save();
response = "login successful";
} else {
response = "Password doesn't match"
}
} else {
response = "User not found";
}
}
return response;
}
#Mutation(() => String)
async logout(#Ctx() ctx: any) {
let sess = ctx.req.session;
if (!sess.userId) { return "already logged out"; }
else{
sess.destroy();
return "logged out";
}
}
I want to get user property in session after login, but when i set session after login, socket.request.session doesn't change, there is no user property in it. But i can get it in router.post.
I tried to edit sessions in router.post()/router.get(), socket.request.session was still not change.
index.js
const io = require('socket.io').listen('8082', { origins: '*' })
const schedule = require('node-schedule')
io.set('transports', [
'websocket',
'flashsocket',
'htmlfile',
'xhr-polling',
'jsonp-polling',
'polling'
])
io.set('origins', '*:*')
const app = new express()
const sessionStore = new session.MemoryStore({ reapInterval: 3600 * 1000 })
const sessionMiddleware = session({
secret: 'Stefanie Sun',
store: sessionStore,
resave: false,
saveUninitialized: true,
cookie: {
maxAge: 8 * 3600 * 1000,
secure: false
},
rolling: true
})
io.use((socket, next) => {
sessionMiddleware(socket.request, socket.request.res, next);
})
app.use(sessionMiddleware)
routes(app)
io.on('connection', (socket) => {
const comment_schedule = schedule.scheduleJob('*/10 * * * * *', async () => { /** 10s查询一次是否有新的内容 **/
const COOKIE_STR = socket.request.session
console.log(COOKIE_STR)
})
})
router.js
...
router.post('/pagelist', (req, res, next) => {
req.session.user = { username: 'test1', gender: 'x', bio: 'this is a test' }
console.log(req.session)
res.status(200).json({ code: 'OK' })
}
app.user('/api/page', router)
when i visited /api/page/pagelist after signin, i wish i can get the same session in socket.request and req.session in router.post,
but socket.request.session is
Session {
cookie:
{ path: '/',
_expires: 2019-04-07T22:57:13.379Z,
originalMaxAge: 28800000,
httpOnly: true,
secure: false } }
but in router.post req.session is
Session {
cookie:
{ path: '/',
_expires: 2019-04-07T22:57:48.146Z,
originalMaxAge: 28799999,
httpOnly: true,
secure: false },
user:
{
username: 'test1',
gender: 'x',
bio: 'this is a test'
}}
i hope in socket.request.session i can also get
user property.
My fontend project is with Vue.js. And i set socket.on('event') in home.vue. I connect socket.io before the page logins, and after login i set user property in session, i can't get this property in socket.request.session.
login code in frontend
// api.js
export const loginApi = ({ username, password } = { username: '', password: '' }) => {
const data = {
username,
password
};
return axios.request({
url: '/api/signin',
data: qs.stringify(data),
method: 'post'
})
}
// login.vue
submit() {
loginApi({ username: this.username, password: this.password})
.then((result: any) => {
this.$toast.success('login success');
this.Cookies.set('user', this.username, { expires: 7 });
getUserInfo(this.username).then((res: any) => {
const { data } = res;
localStorage.setItem('user', JSON.stringify(data));
const url = this.redirect && this.redirect || '/pages';
this.$router.push(url);
})
})
}