Comments (3)
in the .ejs files use csrf properly
from passport.
It would be appreciated if you described the problems you are encountering with enough detail that allowed a discussion and proposed fixes. Feedback is always welcome, but complaints alone are not actionable.
from passport.
hey, I already solve the issue. In the documentation no mention of csrf in .ejs file. And without it i was getting constant error. Only when i added them i got the thing running. Plus now i have the full backend written properly - with signin , signup with jwtToken and the google, facebook using passport. But i could not have done this only by your documentation.
My full code
import express from 'express'
import cors from 'cors'
import { MongoClient, Binary } from 'mongodb'
import uri from './first.js'
import bcrypt from 'bcrypt'
import jwt from 'jsonwebtoken'
import session from 'express-session'
import crypto from 'crypto'
import nodemailer from 'nodemailer'
import multer from 'multer'
import NodeCache from 'node-cache'
import imageType from 'image-type'
import passport from 'passport'
import { Strategy as GoogleStrategy } from 'passport-google-oauth20'
import { Strategy as FacebookStrategy } from 'passport-facebook'
import cookieSession from 'cookie-session'
import a from './env.js'
import dotenv from 'dotenv'
dotenv.config()
const transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: a.EMAIL,
pass: a.PASSWORD
},
})
const client = new MongoClient(uri)
const app = express()
app.use(cors())
app.use(express.json())
const jwtSecret = process.env.JWT_SECRET
const imageCache = new NodeCache();
app.use(
cookieSession({
name: 'session',
keys: process.env.COOKIE_SECRET,
maxAge: 24 * 60 * 60 * 1000, // 1 day
})
);
app.use(passport.initialize());
app.use(passport.session());
// Define your Google OAuth 2.0 credentials
const googleClientId = process.env.GOOGLE_CLIENT_ID
const googleClientSecret = process.env.GOOGLE_CLIENT_SECRET
// Define your Facebook OAuth 2.0 credentials
const facebookAppId = process.env.FACEBOOK_APP_ID
const facebookAppSecret = process.env.FACEBOOK_APP_SECRET
passport.use(
new GoogleStrategy(
{
clientID: googleClientId,
clientSecret: googleClientSecret,
callbackURL: '/auth/google/callback', // Define your callback URL
},
(accessToken, refreshToken, profile, done) => {
// Handle Google authentication here
// You can save the user profile data to your database or perform other actions
return done(null, profile);
})
);
// Passport setup for Facebook OAuth 2.0
passport.use(
new FacebookStrategy(
{
clientID: facebookAppId,
clientSecret: facebookAppSecret,
callbackURL: '/auth/facebook/callback', // Define your callback URL
},
(accessToken, refreshToken, profile, done) => {
// Handle Facebook authentication here
// You can save the user profile data to your database or perform other actions
return done(null, profile);
})
);
// Serialize and deserialize user (required for session support)
passport.serializeUser((user, done) => {
done(null, user);
});
passport.deserializeUser((user, done) => {
done(null, user);
});
async function startServer() {
try {
await client.connect()
const db = client.db('store')
const collection = db.collection('user_registration_information')
const friends = db.collection('allfriends')
const finalfriendslist = db.collection('finalfriendslist')
app.get('/', (req, res) => {
const data = { showHome: true }
res.json(data)
})
// Define routes for initiating Google and Facebook authentication
app.get(
'/auth/google',
passport.authenticate('google', {
scope: ['profile', 'email'], // Define the required scopes
})
);
app.get(
'/auth/facebook',
passport.authenticate('facebook', {
scope: ['public_profile', 'email'], // Define the required scopes
})
);
// Define the callback routes for Google and Facebook authentication
app.get(
'/auth/google/callback',
passport.authenticate('google', { failureRedirect: '/Login-Page-Form' }),
async(req, res) => {
// Successful Google authentication
const user = req.user
await collection.insertOne(user);
res.redirect('/LoggedInHomePage'); // Redirect to the profile page or any other page
}
);
app.get(
'/auth/facebook/callback',
passport.authenticate('facebook', { failureRedirect: '/Login-Page-Form' }),
async(req, res) => {
// Successful Facebook authentication
const user = req.user
await collection.insertOne(user);
res.redirect('/LoggedInHomePage'); // Redirect to the profile page or any other page
}
);
app.use(session({
secret: jwtSecret,
resave: false,
saveUninitialized: false
}));
/* ------------------------------------------------------------------------------------------------------------ */
// *! Handles the upload of profile pictures. See ProfileImage.js
// Function to determine the content type of the image
function getImageContentType(imageData) {
const type = imageType(Buffer.from(imageData)); // imageType library expects a buffer as its argument so imageData is converted to buffer before passing it to imageType
if (type) {
return `image/${type.ext}`;
}
// Default to PNG content type if not recognized
return 'image/png';
}
const upload = multer({ storage: multer.memoryStorage() });
// Handle image upload
app.post('/upload', upload.single('image'), async(req, res) => {
console.log('Post upload entry')
if (!req.file) {
console.log('No image uploaded')
return res.status(400).send('No image uploaded');
}
console.log('Image file is found')
const authHeader = req.headers.authorization
const token = authHeader && authHeader.split(' ')[1]
console.log('Entering check token')
if (!token) {
// No JWT provided
console.log('Unauthorized')
res.status(401).send('Unauthorized')
return
}
let userEmail;
console.log('After userEmail')
try {
// Verify JWT
const decoded = jwt.verify(token, jwtSecret)
userEmail = decoded.email
console.log('Token verified')
}
catch (error) {
// Invalid JWT
console.log('Forbidden')
res.status(403).send('Forbidden')
}
// Buffer.from is a method provided by Node.js's built-in Buffer module. It is used to create a new Buffer object from various sources, including binary data.
// req.file.buffer: The buffer property of the req.file object contains the binary data of the uploaded file. The Binary class is a part of the MongoDB Node.js driver. It is used to represent binary data, such as images, in a format that MongoDB can handle.
const imageBuffer = Buffer.from(req.file.buffer);
const imageBinary = new Binary(imageBuffer);
await collection.updateOne(
{ email: userEmail },
{ $set: { filename: req.file.originalname, image: imageBinary } }
);
// Serialize the imageBinary before storing it in the cache
const imageBinarySerialized = imageBinary.buffer.toString('base64');
imageCache.set(userEmail, imageBinarySerialized); // responsible for storing the image data in an image cache, associating it with the user's email address
console.log('Image uploaded');
return res.status(200).send('Image upload successful');
});
app.use(express.static('public'));
app.get('/user/image', async (req, res) => {
// Verify the user's token and extract their email
console.log('Entered server side /user/image')
const authHeader = req.headers.authorization;
const token = authHeader && authHeader.split(' ')[1];
if (!token) {
return res.status(401).send('Unauthorized');
}
let userEmail;
try {
const decoded = jwt.verify(token, jwtSecret);
userEmail = decoded.email;
console.log('Token Verified')
}
catch (error) {
return res.status(403).send('Forbidden');
}
// When retrieving from the cache, deserialize the data
const cachedImageSerialized = imageCache.get(userEmail);
if (cachedImageSerialized) {
try {
console.log('Enter if cachedImage')
const cachedImageBinary = new Binary(Buffer.from(cachedImageSerialized, 'base64'));
const imageContentType = getImageContentType(cachedImageBinary);
res.setHeader('Content-Type', imageContentType);
res.send(cachedImageBinary.buffer); // you are sending the raw binary image data as the response body
}
catch (error) {
console.error('Error serving cached image:', error);
res.status(500).send('Internal Server Error');
}
}
else {
try {
// Retrieve user's image data from the database
const user = await collection.findOne({ email: userEmail });
console.log('Retrieve user image data from the database')
if (!user || !user.image) {
console.log('User or image data not found')
return res.status(404).send('User or image data not found');
}
const imageBinary = user.image
// Serialize the imageBinary before storing it in the cache
const imageBinarySerialized = imageBinary.buffer.toString('base64');
imageCache.set(userEmail, imageBinarySerialized);
// Serve the image
try {
console.log('Serve the image');
const imageSerialized = imageCache.get(userEmail); // if there is image in the cache it returns true
if (imageSerialized) {
const imageBinary = new Binary(Buffer.from(imageSerialized, 'base64'));
const imageContentType = getImageContentType(imageBinary);
res.setHeader('Content-Type', imageContentType);
res.send(imageBinary.buffer);
}
else {
// This could happen if there was an issue with caching the image data
res.status(404).send('Image not found in cache');
}
}
catch (error) {
console.error('Error serving retrieved image:', error);
res.status(500).send('Internal Server Error');
}
}
catch (error) {
console.error('Error retrieving image from database:', error);
res.status(500).send('Internal Server Error');
}
}
});
/* ------------------------------------------------------------------------------------------------------------- */
// *! See ProfileForm.js , Here the user inputs his personal information
app.put('/updateProfile', async(req, res) => {
const authHeader = req.headers.authorization;
const token = authHeader && authHeader.split(' ')[1];
if (!token) {
return res.status(401).send('Unauthorized');
}
let email;
try {
const decoded = jwt.verify(token, jwtSecret);
email = decoded.email;
console.log('Token Verified for updateProfile')
}
catch (error) {
return res.status(403).send('Forbidden');
}
const response = await collection.updateOne(
{ email: email },
{ $set: { fullname: req.body.name, dob: req.body.dob, school: req.body.school, college: req.body.college, university: req.body.uni, workplace: req.body.workplace } }
);
if (response.modifiedCount === 1) {
console.log('Profile updated successfully');
res.sendStatus(200);
} else {
console.log('Profile update failed');
res.sendStatus(500); // Internal Server Error
}
})
app.get('/userProfileData', async(req, res) => {
const authHeader = req.headers.authorization;
const token = authHeader && authHeader.split(' ')[1];
if (!token) {
return res.status(401).send('Unauthorized');
}
let email;
try {
const decoded = jwt.verify(token, jwtSecret);
email = decoded.email;
console.log('Token Verified for updateProfile')
const user = await collection.findOne({ email: email });
if (!user) {
return res.status(404).send('User profile not found');
}
res.send(user)
}
catch (error) {
return res.status(403).send('Forbidden');
}
})
/* -------------------------------------------------------------------------------------------------------------- */
app.get('/logout', (req, res) => {
req.session.destroy((err) => {
if (err) {
console.log(err);
res.status(500).send('Error occurred during logout');
}
else {
res.clearCookie('authToken');
res.redirect('/')
}
});
});
// Verifies the JWT and authenticates the user
app.get('/protected-route', (req, res) => {
// Get JWT from Authorization header
const authHeader = req.headers.authorization
const token = authHeader && authHeader.split(' ')[1]
if (!token) {
// No JWT provided
console.log('Unauthorized')
res.status(401).send('Unauthorized')
return
}
try {
// Verify JWT
const decoded = jwt.verify(token, jwtSecret)
let email = decoded.email
// Authentication successful
res.status(200).send(email)
}
catch (error) {
// Invalid JWT
console.log('Forbidden')
res.status(403).send('Forbidden')
}
})
// Verify email route
app.get('/verify', async (req, res) => {
const verificationToken = req.query.token
console.log('verificationToken = ',verificationToken)
try {
// Find the user in the database based on the verification token
const user = await collection.findOne({ verificationToken })
console.log('user = ', user)
if (!user) {
// User not found or already verified
console.log('Invalid verification token')
res.status(404).send('Invalid verification token')
return
}
console.log('entered verify token email')
// Update the user's status to "verified" in the database
await collection.updateOne(
{ _id: user._id },
{ $set: { verified: true }, $unset:{ verificationToken: 1 } }
)
console.log('exit update email token to true')
res.status(200).json({ message: 'Email verified successfully' });
// Redirect the user to a success page or display a success message
// res.redirect('/LoginPage')
}
catch (error) {
console.log(error.message)
res.status(500).send('Error verifying email')
}
})
app.get('/verify-forgot-password-email', async (req, res) => {
const verificationToken = req.query.resetToken;
try {
// Find the user in the database based on the verification token
const user = await collection.findOne({ verificationToken: verificationToken });
if (!user) {
console.log('Invalid verification token from forgot password')
// User not found or already verified
return res.status(404).send('Invalid verification token');
}
console.log('entered verify token email for forgot password')
// Update the user's status to "verified" in the database
await collection.updateOne(
{ _id: user._id },
{ $set: { verified: true } }//resetToken: null, resetTokenExpiresAt: null
);
console.log('exit update email token to true for forgot password')
res.status(200).json({ message: 'Email verified successfully for forgot password' });
}
catch (error) {
console.log(error);
res.status(500).send('Error verifying email');
}
});
// For the form inside About.js on the client side
app.post('/submit-form', async (req, res) => {
try {
await collection.insertOne(req.body)
res.status(200).send('Form data saved') /* On the client-side, when making the Axios POST request
to /submit-form, if the server responds with a status of 200 (OK), the client-side code enters the .then block. */
} catch (error) {
console.log(error)
res.status(500).send('Error saving form data')
}
})
// Define the sendVerificationEmail function
function sendVerificationEmail(email, verificationToken) {
const mailOptions = {
from: '[email protected]',
to: email,
subject: 'Account Verification',
html: `<p>Hello,</p>
<p>Thank you for registering. Please verify your email address by clicking the following link:</p>
<a href="http://localhost:3000/verify?token=${verificationToken}">Verify Email</a>`,
};
transporter.sendMail(mailOptions, (error, info) => {
if (error) {
console.log(error);
// Handle error while sending verification email
}
else {
console.log('Verification email sent - from nodemailer');
// Handle successful sending of verification email
}
});
}
// For the form inside Register_Page.js on the client side
app.post('/Register-Page-Form', async (req, res) => {
const {text, email, password} = req.body
try {
let userExist = await collection.findOne({email})
if(userExist){
res.status(200).send({ message : 'This email already exists. Please Login'})
}
else{
const hashedPassword = await bcrypt.hash(password, 10);
const verificationToken = generateVerificationToken();
const user = {
username: text,
email: email,
password: hashedPassword,
verified: false,
verificationToken: verificationToken
};
await collection.insertOne(user)
console.log('User in database')
res.status(200).send({ message : 'User registered successfully. Please Login'})
sendVerificationEmail(email, verificationToken);
}
}
catch (error) {
console.log(error)
res.status(500).send('Error saving form data')
}
})
// Function to generate verification token
function generateVerificationToken() {
return crypto.randomBytes(20).toString('hex');
}
function forgotPasswordToken(email, resetToken){
const mailOptions = {
from: '[email protected]',
to: email,
subject: 'Account Verification',
html: `<p>Hello,</p>
<p>Enter the new Password by clicking the following link:</p>
<a href="http://localhost:3000/verify-forgot-password-email?resetToken=${resetToken}">Verify Email</a>`,
};
transporter.sendMail(mailOptions, (error, info) => {
if (error) {
console.log(error);
// Handle error while sending verification email
}
else {
console.log('Verification email sent- from nodemailer for forgot password');
// Handle successful sending of verification email
}
});
}
app.post('/Forgot-Password', async(req, res) => {
const {email} = req.body
try{
let userExist = await collection.findOne({email})
if (!userExist) {
console.log('Email not found in Forgot-Password snippet')
// User with the provided email doesn't exist
return res.status(404).send('User not found');
}
const resetToken = generateVerificationToken()
console.log('Reset Token in Forgot-Password snippet = ', resetToken)
// Save the reset token and its expiration in the user document in your database
await collection.updateOne(
{ _id: userExist._id },
{
$set: {
resetToken: resetToken,
resetTokenExpiresAt: Date.now() + 3600000,
verified: false,
verificationToken: resetToken
}
}
);
console.log('In Forgot-Password successfully updated in Database')
//console.log('resetTokenExpiresAt = ', resetTokenExpiresAt, 'Current Date = ', Date.now())
forgotPasswordToken(email, resetToken)
res.status(200).send({ email });
}
catch (error) {
console.log(error)
res.status(500).send('Error saving form data')
}
})
app.post('/Forgot-Password-Form', async(req, res) => {
const { resetToken, password, email } = req.body;
try{
const user = await collection.findOne({ verificationToken: resetToken });
console.log('Hi i am Forgot-Password-Form')
if (!user) {
// User not found or the reset token is invalid
console.log('User with the email not found in Forgot-Password-Form')
return res.status(404).send('Invalid reset token');
}
console.log('User exists and Current Date = ', Date.now())
// Check if the reset token has expired
if (user.resetTokenExpiresAt < Date.now()) {
// Reset token has expired
console.log('Reset token has expired')
return res.status(400).send('Reset token has expired');
}
console.log('Reset Token has not expired, Hurray !!!!!')
const newPassword = await bcrypt.hash(password, 10);
console.log('Hashed Password done')
await collection.updateOne(
{ _id: user._id },
{
$set: {
password: newPassword,
resetToken: null,
verificationToken: null,
resetTokenExpiresAt: null
}
}
);
console.log('Password reset successfully')
// Redirect the user to the login page or send a success response
res.sendStatus(200);
}
catch(error){
console.log(error)
res.status(500).send('Error Resetting Password')
}
})
// ! For the form inside Login_Page.js on the client side
app.post('/Login-Page-Form', async (req, res) => {
const {email, password} = req.body
try {
let userExist = await collection.findOne({email}) // returns the entire document and so userExist contains both email and password
if(userExist){
const isPasswordMatch = await bcrypt.compare(password, userExist.password);
console.log(password)
if(isPasswordMatch){
if(userExist.verified){
const token = jwt.sign({email}, jwtSecret, {expiresIn: '10h'})
console.log(token)
res.status(200).send({token})
return
}
else{
console.log('Please verify your email before logging in')
res.status(401).send({ message: 'Please verify your email before logging in' });
return;
}
}
else{
console.log('Invalid email or password')
res.status(401).send({ message: 'Invalid email or password' });
return
}
}
else{
console.log('Hmmmm')
res.redirect('/')
return
}
}
catch (error) {
console.log(error)
res.status(500).send('Error saving form data')
}
})
/ -------------------------------------------------------------------------------------------------------------- */
app.listen(5000, () => {
console.log('App is running')
})
}
catch (error) {
console.log(error)
}
}
startServer()
from passport.
Related Issues (20)
- strategy.authenticate is not a function (passport-facebook)
- Race condition in logout function HOT 10
- Laravel passport HOT 2
- Passport 0.6.0 regenerates session IDs, breaking custom logins
- Facebook Tutorial Register has no content HOT 1
- Prompt option is being ignored in nodejs when extending PassportStrategy
- Documentation Isuue HOT 1
- Passport authentication with client side generation
- Only one user session is created instead of a new session for each different logged in user
- Duplicate Session Save Operations During Login with Session Regeneration
- How to add passportjs in Saleforce commerce cloud web site SFRA ?
- Using AuthenticationCallback/req.logIn() breaks deserialization in 0.7.0
- Passpor-discord with Framework Astrojs
- social login with yahoo using passprt js HOT 1
- https://www.passportjs.org/packages/ not found
- Passport Strategy for Facebook doesn't work
- local strategy deserializeUser not be used
- Add Discord Auth Strategy
- Add my Passport Strategies to website: Magalu (Magazine Luiza) and MercadoLivre (ML Brazil)
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from passport.