how to delete cookie without reloading the page using custom express server in next js - express

this is my routes file
const User = require("./schema");
const jwt = require("jsonwebtoken");
const bcrypt = require("bcrypt");
const express = require("express");
const server2 = express();
const routes = (server,app) => {
// this route is for signup
server.post("/api/signup", async (req,res) => {
const { fullName, emailId, password }=req.body;
const signupData = new User({
fullName,
emailId,
password: await bcrypt.hash(password,10),
});
const token = await signupData.generateToken();
console.log(`token: ${token}`);
if (token != undefined) {
res.cookie("token",token,{
httpOnly: true,
secure: true,
sameSite: "strict",
path: "/",
maxAge: 1000*60*2
})
res.send({message:"signedup successfuly"});
res.end();
}
const saveUser = await signupData.save();
});
// this route is for user varification
server.get("/api", async (req,res) => {
const token = req.cookies.token;
console.log(`token: ${token}`);
if (token != undefined) {
const _id = jwt.verify(token,process.env.JWT_SECRET)._id;
const findUser = await User.findOne({ _id });
res.send(findUser);
} else {
res.send({fullName:""});
}
});
// this route is for logout
server.get("/api/logout",async (req, res) => {
try {
const token = req.cookies.token;
const _id = jwt.verify(token, process.env.JWT_SECRET)._id;
await User.updateOne({ _id }, { $pull: { tokens: { token }}});
res.clearCookie("token");
console.log(req.cookies.token)
res.send({message:""})
res.end();
} catch(err) {
console.log(err)
}
});
}
module.exports = routes;
When I do signup cookie is setting without reloading the page its working but that's not a problem the problem is when I do logout its not deleting cookie without reloading the page when I reload the page its working but without reloading the page its not working I am using custom express server in nextjs

Related

How to display logged in username on the screen | express session

I want take the user info like email , username and display it on dashboard.ejs . i tried req.session.username and req.body.username but never worked . please help me in this !!
i want handle profile management for the web so by retriving the username help fetch the info about the user in the database
`
const express = require("express");
const app = express();
const bcrypt = require("bcryptjs");
const session = require("express-session");
const MongoDBSession = require("connect-mongodb-session")(session);
const mongoose = require("mongoose");
const UserModel = require("./models/user");
const mongoURI = "mongodb://localhost:27017/sessions";
mongoose.connect( mongoURI, {
useNewUrlParser : true,
// useCreateIndex : true,
// useUnifiedToplogy : true
}).then((res)=>{
console.log("MongoDB connected");
})
const store = new MongoDBSession({
uri : mongoURI,
collections : "mySessions"
})
const isAuth = (req,res,next)=>{
if(req.session.isAuth){
next();
}else{
res.redirect("/login");
}
}
app.use(session({
secret : "key that will sign a cookie",
resave : false,
saveUninitialized : false,
store : store
}))
app.set("view engine", "ejs");
app.use(express.urlencoded({ extended: true }));
app.get("/", (req,res)=>{
res.render("landing");
});
// Login Page
app.get("/login", (req,res)=>{
res.render("login");
} );
app.post("/login", async(req,res)=>{
const {email , password} = req.body;
const user = await UserModel.findOne({email});
if (!user){
return res.redirect("/login");
}
const isMatch =await bcrypt.compare(password , user.password);
if(!isMatch){
return res.redirect("/login");
}
req.session.isAuth = true;
res.redirect("/dashboard");
});
// Register Page
app.get("/register", (req,res)=>{
res.render("register");
});
app.post("/register", async (req,res)=>{
const {username , email , password } = req.body;
let user = await UserModel.findOne({email});
if (user){
return res.redirect("/register");
}
const hashPsw =await bcrypt.hash(password,12);
user = new UserModel({
username,
email,
password:hashPsw
});
user.save();
console.log("saved");
if (!user){
return res.redirect("/login");
}
const isMatch =await bcrypt.compare(password , user.password);
if(!isMatch){
return res.redirect("/login");
}
req.session.isAuth = true;
res.redirect("/dashboard");
});
// Dashboard Page
app.get("/dashboard", isAuth , (req,res)=>{
console.log(req.session);
res.render("dashboard");
});
app.post("/logout", (req,res)=>{
req.session.destroy((err)=>{
if (err) throw err;
res.redirect("/");
})
});
app.listen(3500 , ()=>{
console.log("server running on port 3500");
})
`
One of the options would be to supply that in the POST request's response. For example, Author has inserted it in a pug view here like h2 Username: #{user.name} and has supplied it as variable while page rendering in response here with res.render('profile', {title: "My Profile", user: req.cookies.userData});.
Since you have used ejs instead of pug, the injecting I did with #{} can be done with <%= YOUR_VARIABLE %> . Please, see this for a tutorial and ejs docs for more examples.

Express-jwt is not returning any response

I'm trying to create a Login functionality using express-jwt, and using the middleware function in my app.js file. But whenever I'm trying to send a get request using the postman, it sending request for infinite of time and never returns back any error or success message.
I'm using dynamoDB as database.
here's my Login.js file
const AWS = require("aws-sdk");
const express = require("express");
const bcrypt = require("bcrypt");
const jwt = require("jsonwebtoken");
require("dotenv").config();
AWS.config.update({ region: "us-east-2" });
const docClient = new AWS.DynamoDB.DocumentClient();
const router = express.Router();
router.post("/login", (req, res) => {
user_type = "customer";
const email = req.body.email;
docClient.get(
{
TableName: "users",
Key: {
user_type,
email,
},
},
(err, data) => {
if (err) {
res.send("Invalid username or password");
} else {
if (data && bcrypt.compareSync(req.body.password, data.Item.password)) {
const token = jwt.sign(
{
email: data.Item.email,
},
process.env.SECRET,
{ expiresIn: "1d" }
);
res.status(200).send({ user: data.Item.email, token: token });
} else {
res.status(400).send("Password is wrong");
}
}
}
);
});
module.exports = router;
Here's my jwt.js file:
const expressJwt = require("express-jwt");
require("dotenv").config();
function authJwt() {
const secret = process.env.SECRET;
return expressJwt({
secret,
algorithms: ["HS256"],
});
}
module.exports = authJwt;
And I'm trying to use the expressJwt like this in my app.js file:
app.use(authJwt); //If I'm not using this, then the code works fine without API protection
Can Anyone tell me what's wrong with my code?
Any help from your side is appreciated.
Remove function from your jwt.js ,it should look like this
const expressJwt = require('express-jwt');
const secret = process.env.secret
const authJwt = expressJwt({
secret,
algorithms:['HS256']
})
module.exports = authJwt;

Jest testing of async middleware for authentication

I'm using a static array to scaffold a user table, prior to refactoring with actual postgres db and some fetch()-ing code. At present, the tests work, but obviously they are working synchronously. Here's the placeholder API code:
// UserAPI.js
let findUserById = (credentials = {}) => {
const { userId } = credentials
if (userId) {
const foundUser = users.find(user => user.id === userId)
if (foundUser !== undefined) {
const { password: storedpassword, ...user } = foundUser
return user
}
}
return null
}
exports.byId = findUserById
And an example test as follows:
// excerpt from TokenAuth.test.js
const UserAPI = require('../lib/UserAPI')
describe('With TokenAuth middleware', () => {
beforeEach(() => {
setStatus(0)
})
it('should add user to req on authorised requests', () => {
const token = createToken(fakeUser)
const authReq = { headers: { authorization: 'Bearer ' + token } }
const myMiddleware = TokenAuth(UserAPI.byId)
myMiddleware(authReq, fakeRes, fakeNext)
// expect(authReq.user).toStrictEqual({ id: 1, username: 'smith#example.com' });
expect(authReq.user.username).toStrictEqual('smith#example.com')
expect(authReq.user.id).toStrictEqual(1)
})
})
This runs fine, and along with other tests gives me the coverage I want. However, I now want to check that the tests will deal with the async/await nature of the fetch() code I'm going to use for the proper UserAPI.js file. So I re-write the placeholder code as:
// UserAPI.js with added async/await pauses ;-)
let findUserById = async (credentials = {}) => {
const { userId } = credentials
// simulate url resolution
await new Promise(resolve => setTimeout(() => resolve(), 100)) // avoid jest open handle error
if (userId) {
const foundUser = users.find(user => user.id === userId)
if (foundUser !== undefined) {
const { password: storedpassword, ...user } = foundUser
return user
}
}
return null
}
exports.byId = findUserById
... at which point I start getting some lovely failures, due I think it's returning unresolved promises.
My problem is two-fold:
How should I alter the UserAPI.test.js tests to deal with the new async nature of findUserByCredentials() ?
Am I ok in my assumption that ExpressJS is happy with async functions as request handlers? Specifically, due to the async nature ofUserAPI.findUserByCredentials is this ok?
Main App.js uses curried UserAPI.byId() for the findUserById.
// App.js (massively simplified)
const express = require('express')
const TokenAuth = require('./middleware/TokenAuth')
const RequireAuth = require('./middleware/RequireAuth')
const UserAPI = require('./lib/UserAPI')
let router = express.Router()
const app = express()
app.use(TokenAuth(UserAPI.byId))
app.use(RequireAuth)
app.use('/users', UserRouter)
module.exports = app
My TokenAuth middleware would now run along these lines:
// TokenAuth.js (simplified)
const jwt = require('jsonwebtoken')
require('dotenv').config()
const signature = process.env.SIGNATURE
let TokenAuth = findUserById => async (req, res, next) => {
let header = req.headers.authorization || ''
let [type, token] = header.split(' ')
if (type === 'Bearer') {
let payload
try {
payload = jwt.verify(token, signature)
} catch (err) {
res.sendStatus(401)
return
}
let user = await findUserById(payload)
if (user) {
req.user = user
} else {
res.sendStatus(401)
return
}
}
next()
}
module.exports = TokenAuth
A partial answer us simply to add an async/await on the middleware call:
it('should add user to req on authorised requests', async () => {
const token = createToken(fakeUser)
const authReq = { headers: { authorization: 'Bearer ' + token } }
const myMiddleware = TokenAuth(UserAPI.byId)
await myMiddleware(authReq, fakeRes, fakeNext)
// expect(authReq.user).toStrictEqual({ id: 1, username: 'smith#example.com' });
expect(authReq.user.username).toStrictEqual('smith#example.com')
expect(authReq.user.id).toStrictEqual(1)
})

401: unauthorized (it contains bearer token)

Login module is working and creating users with token 201 created
Receipts route had worked with the same code before but now response is 401
using Postman (Authorization & Bearer: xcvbnm) has been put
Here is my code
server.js
const express = require('express')
require('./db/mongoose')
const userRouter = require('./routes/user')
const receiptRouter = require('./routes/receipt')
const app = express()
const port = process.env.PORT || 4003
app.use(express.json())
app.use(userRouter)
app.use(receiptRouter)
app.listen(port, () => {
console.log('Server is up on port ' + port)
})
const Receipt = require('./models/receipt')
const User = require('./models/user')
Receipts Route
router.post('/receipts', auth, async (req, res) => {
const receipt = new Receipt({
...req.body,
owner: req.user._id
})
try {
await receipt.save()
res.status(201).send(receipt)
} catch (e) {
res.status(400).send(e)
}
})
Receipt Schema
const Receipt = mongoose.model('Receipt', {
description: {
type: String,
required: true,
trim: true
},
})
Auth module
const auth = async (req, res, next) => {
try {
const token = req.header('Authorization').replace('Bearer', '')
const decoded = jwt.verify(token, 'Mango#123')
const user = await User.findOne({ _id: decoded._id, 'tokens.token': token })
if (!user) {
throw new Error()
}
req.token = token
req.user = user
next()
} catch (e) {
res.status(401).send({ error: 'Please authenticate.' })
}
}

Request origin cannot be verified - Shopify

I'm developing an app for Shopify. Currently under development stage. Until now, I have successfully managed to authorise the app and then redirect it back to admin page using the Embedded App SDK. However, when I return to the admin page, it gives me an error saying Request origin cannot be verified.
The console shows Failed to load resource: the server responded with a status of 403 (Forbidden)
The URL in the console is something like this https://myshop.myshopify.com/admin/apps/dfdjf4343343434343434bfdf/shopify/shopify/callback?code=ffdfdffd&hmac=fdfdfdfdfdfdfdfdfddfdfdfdfdf&shop=myshop.myshopify.com&state=151193864548800&timestamp=1511938648
The fdfdfdfdfdfdfdfdfddfdfdfdfdf are just random characters that I've replaced instead of a hash. FYI - I've removed the app name and user profile name and avatar from the image.
This is happening because, you are unable to match state, that is set in cookie, while responding with redirect url
const ShopifyToken = require('shopify-token')
const forwardingAddress = process.env.HOST
const shopifyToken = new ShopifyToken({
sharedSecret: process.env.SHOPIFY_API_SECRET,
redirectUri: forwardingAddress + '/shopify/callback',
apiKey: process.env.SHOPIFY_API_KEY
})
const shopify = {
// use this for authentication
auth: (req, res, next) => {
const shop = req.query.shop
if (!shop) {
return res.status(400).send('Missing shop parameter. Please add ?shop=your-development-shop.myshopify.com to your request')
}
const shopRegex = /^([\w-]+)\.myshopify\.com/i
const shopName = shopRegex.exec(shop)[1]
const state = shopifyToken.generateNonce()
const url = shopifyToken.generateAuthUrl(shopName, scopes, state)
res.cookie('state', state)
res.redirect(url)
},
// use this as your callback function
authCallback: async (req, res) => {
const { shop, hmac, code, state } = req.query
const stateCookie = cookie.parse(req.headers.cookie).state
if (state !== stateCookie) {
// you are unable to set proper state ("nonce") in this case, thus you are getting this error
return res.status(403).send('Request origin cannot be verified')
}
if (!shop || !hmac || !code) {
res.status(400).send('Required parameters missing')
}
let hmacVerified = shopifyToken.verifyHmac(req.query)
console.log(`verifying -> ${hmacVerified}`)
// DONE: Validate request is from Shopify
if (!hmacVerified) {
return res.status(400).send('HMAC validation failed')
}
const accessToken = await shopifyToken.getAccessToken(shop, code)
const shopRequestUrl = 'https://' + shop + '/admin/shop.json'
const shopRequestHeaders = {
'X-Shopify-Access-Token': accessToken
}
try {
const shopResponse = await request.get(shopRequestUrl, { headers: shopRequestHeaders })
res.status(200).end(shopResponse)
} catch (error) {
res.status(error.statusCode).send(error.error.error_description)
}
}
}
Simple as this is, also make sure that the protocol matches from what you typed in to start the app install.
If you accidentally use http for http://you.ngrok.io/ but your callback redirects to https (i.e. https://you.ngrok.io/auth/callback), the OAuth handshake will fail.
const express = require('express');
const router = express.Router();
const dotenv = require('dotenv').config();
const cookie = require('cookie');
const requestPromise = require('request-promise');
const ShopifyToken = require('shopify-token');
const scopes = "write_products";
const forwardingAddress = process.env.HOST;
var shopifyToken = new ShopifyToken({
sharedSecret: process.env.SHOPIFY_API_SECRET,
redirectUri: forwardingAddress + '/shopify/callback',
apiKey: process.env.SHOPIFY_API_KEY
})
router.get('/shopify', (req, res) => {
const shop = req.query.shop;
if (!shop) {
return res.status(400).send('Missing shop parameter. Please add ?shop=your-development-shop.myshopify.com to your request')
}
const shopRegex = /^([\w-]+)\.myshopify\.com/i
const shopName = shopRegex.exec(shop)[1]
const state = shopifyToken.generateNonce();
const url = shopifyToken.generateAuthUrl(shopName, scopes, state);
res.cookie('state', state);
res.redirect(url);
});
router.get('/shopify/callback', (req, res) => {
const { shop, hmac, code, state } = req.query;
const stateCookie = cookie.parse(req.headers.cookie).state;
if (state !== stateCookie) {
// you are unable to set proper state ("nonce") in this case, thus you are getting this error
return res.status(403).send('Request origin cannot be verified')
}
if (!shop || !hmac || !code) {
res.status(400).send('Required parameters missing')
}
let hmacVerified = shopifyToken.verifyHmac(req.query)
console.log(`verifying -> ${hmacVerified}`)
// DONE: Validate request is from Shopify
if (!hmacVerified) {
return res.status(400).send('HMAC validation failed')
}
const accessToken = shopifyToken.getAccessToken(shop, code);
const shopRequestUrl = 'https://' + shop + '/admin/products.json'
const shopRequestHeaders = {
'X-Shopify-Access-Token': accessToken
}
try {
const shopResponse = requestPromise.get(shopRequestUrl, { headers: shopRequestHeaders })
res.status(200).send(shopResponse)
} catch (error) {
res.status(error.statusCode).send(error.error.error_description)
}
});
module.exports = router;