i'm just checking that this is expected behaviour while using the emulator. my public firebase webapp doesn't have this issue but while running the emulator, after a couple of reloads, my page reloads slower than usual and renders the view displayed when the user is signed out. these are the relevant endpoints:
app.post("/api/login", (req, res) => {
const email = req.body.loginEmail;
const password = req.body.loginPassword;
const auth = getAuth();
setPersistence(auth, browserLocalPersistence)
.then(() => {
return signInWithEmailAndPassword(auth, email, password)
.catch((err) => {
console.error("api/login err");
console.error(err);
});
})
.then(() => {
return res.redirect("/");
})
.catch((err) => {
console.error("ERROR API/LOGIN");
console.error(err);
});
});
app.get("/", (req, res) => {
const auth = getAuth();
onAuthStateChanged(auth, (user) => {
if (user) {
getDoc(doc(db, "users", user.uid))
.then((document) => {
const userData = document.data();
const indexPath = path.resolve("./pug/signedin.pug");
res.render(indexPath, {"photoURL": userData.photoURL, "username": userData.displayName}); // this view displays if the user is signed in
})
.catch((err) => {
console.error("error - getdoc index");
console.error(err);
});
} else {
const indexPath = path.resolve("./pug/landing.pug"); // this view displays if the user is signed out
res.render(indexPath);
}
});
});
my auth code authenticates directly with the production database since this is not a project that is public as of yet (i am aware this is a bad practice). the auth emulator is running but i am not using it.
Related
I have built and API with Express to POST a new job in a project I am currently working on. The GET requests work fine, also the DEL, but the POST one is not working. I am connected to a POSTGRES database.
I have defined the following path for the API:
app.use('/api/jobs', jobRoutes);
so when I send a POST request like below:
localhost:4000/api/jobs/createjob
it should work. What is also weird, is that the code was working perfectly before, but now I can't seem to figure it out anymore. I tried looking elsewhere, but I couldn't find any solution when getting this kind of error with APIs.
My API looks like the following:
router.post("/createjob", async (req, res) => {
try {
const {job} = req.body;
const newJob = await pool.query("INSERT INTO job(job_title, job_department, country_id, description, expiration_date) VALUES($1, $2, $3, $4, $5) RETURNING *", [job.job_title, job.job_department, job.country_id, job.description, job.expiration_date]);
res.json(newJob.rows);
} catch (error) {
console.error(error.message);
}
})
I am making the POST request with Postman, and the body looks like this:
{
"description": "job_description",
"job_title": "Back End Developer"
}
When I send the requests, in the terminal shows this error:
Cannot read properties of undefined (reading 'job_title')
Full code of the Routes:
const express = require("express");
const router = express.Router();
const pool = require("../db");
// routes
// get all jobs
router.get('/alljobs', async (req, res) => {
try {
const allJobs = await pool.query("SELECT * FROM job");
res.json(allJobs.rows)
} catch (error) {
console.error(error.message);
}
})
// GET a single job
router.get('/job/:id', async (req, res) => {
try {
const {id} = req.params;
const job = await pool.query("SELECT * FROM job WHERE job_id = $1 ", [id]);
res.json(job.rows)
} catch (error) {
console.error(error.message);
}
})
// create a job
router.post("/createjob", async (req, res) => {
try {
const {job} = req.body;
const newJob = await pool.query("INSERT INTO job(job_title, job_department, country_id, description, expiration_date) VALUES($1, $2, $3, $4, $5) RETURNING *", [job.job_title, job.job_department, job.country_id, job.description, job.expiration_date]);
res.json(newJob.rows);
} catch (error) {
console.error(error.message);
}
})
// update a job
router.patch("/updatejob/:id", async (req, res) => {
try {
const {id} = req.params;
const {description} = req.body;
const updateJob = await pool.query("UPDATE job SET description = $1 WHERE job_id = $2", [description, id]);
res.json(updateJob.rows);
} catch (error) {
console.error(error.message);
}
})
// delete a job
router.delete("/deletejob/:id", async (req, res) => {
try {
const {id} = req.params;
const deleteJob = await pool.query("DELETE FROM job WHERE job_id = $1", [id]);
res.json(deleteJob.rows);
} catch (error) {
console.error(error.message);
}
})
// get all countries
router.get("/countries", async (req, res) => {
try {
const allCountries = await pool.query("SELECT * FROM countries");
res.json(allCountries.rows)
} catch (error) {
console.error(error.message);
}
})
// //create new user
// router.post("/newuser", async (req, res) => {
// try {
// const {user} = req.body;
// const newUser = await pool.query("INSERT INTO users(user_name, email, password, is_candidate, is_recruiter) VALUES($1, $2, $3, $4, $5) RETURNING *", [user.user_name, user.email, user.password, user.candidate, user.recruiter]);
// res.json(newUser.rows);
// } catch (error) {
// console.error(error.message);
// }
// })
module.exports = router;
Full code of my server.js file:
const express = require("express");
const router = require("./routes/jobRoutes");
const jobRoutes = require("./routes/jobRoutes");
const cors = require("cors");
//creates express app
const app = express();
app.use(express.json());
app.use(cors());
//middleware
app.use((req,res,next) => {
console.log("req.path", req.method);
next();
})
app.get("/status", (req, res, next) => {
res.send("connected");
});
// for every other request
app.use('/api/jobs', jobRoutes);
// more middleware
app.use((err, req, res, next) => {
let status = err.status || 500;
let message = err.message;
console.error(err);
return res.status(status).json({
error: { message, status },
});
});
//listen for requests
app.listen(4000, () => {
console.log("listening on port 4000")
});
I tried looking elsewhere, but I couldn't find any solution when getting this kind of error with APIs. The GET and the DEL requests work as expected.
I have this block of code and when a user login, it should set the "access_token" cookie to a token, but when i check the browser application cookie, i see nothing and user is unauthenticated.
const login = async (req, res) => {
try {
const oneUser = await Users.findOne({ username: req.body.username });
if (!oneUser) {
return res.status(403).json("No such user in the database");
}
const isPassword = await bcryptjs.compare(req.body.password, oneUser.password);
if (!isPassword) {
return res.status(500).json("Password is incorrect");
}
const token = jwt.sign(
{
id: oneUser._id,
isAdmin: oneUser.isAdmin,
},
process.env.jwt,
);
const { password, ...others } = oneUser._doc;
res
.cookie("access_token", token)
.status(200)
.json({ ...others });
} catch (err) {
res.status(500).json(err);
}
};
in the routes auth file i call it like so
router.post("/login", login);
then in my index.html file, i linked the routes up.
app.use("/api/auth", authRoute);
I'm working with React v16 and redux, on the authentication part of a website. I'm using passport and bcrypt to handle my users password (with a middleware in the Model file), encrypt them and save them to my MongoDB database.
To summarise, in the back end I have a route that a route {router.get('/auth/google')} that triggers my passport strategy. And this passport strategy should return a user object.
I want to pass this user object to my front end to save it in my redux state. How can I do this?
I've tried with local storage ( 'localStorage.setItem('user', currentUser)' ) but it didn't work.
Thanks in advance.
In the back end:
Passport.js
//GOOGLE STRATEGY---------------------------------------------------------------------------------
// This google strategy works both for authentication and login in
const GOOGLE_CLIENT_ID = googleConfig.postman.client_id
const GOOGLE_CLIENT_SECRET = googleConfig.postman.client_secret
passport.use(new GoogleStrategy({
clientID: GOOGLE_CLIENT_ID,
clientSecret: GOOGLE_CLIENT_SECRET,
callbackURL: "http://localhost:5000/auth/google/callback", //if success?
},
// cb = callback
async function (accessToken, refreshToken, profile, cb, done) {
console.log("profile", profile);
try {
const currentUser = await MemberModel.findOne({
googleId: profile.id,
});
// In case database doesn't find the user, we must create a new one:
if(!currentUser){
const newUser = await new MemberModel({
googleId:profile.id,
userName:profile.name.familyName,
email: profile.email,
password:null
}).save();
if(newUser){
done(null,newUser);
// My solution. save user in local storage
localStorage.setItem('user', newUser)
}
}
//If the user existed, we are just loggin in:
done(null, currentUser);
// My solution. save user in local storage
localStorage.setItem('user', currentUser)
} catch (error) {
return done(error);
}
}
));
module.exports = passport;
googleAuth.js
router.get('/auth/google',
passport.authenticate('google', { scope: ['profile','email'] }));
router.get('/auth/google/callback',
passport.authenticate('google', { failureRedirect: '/', session:false }),
function(req, res) {
res.redirect("http://localhost:3000");
}
);
membersModel.js
(...)
/* Google authentication doesn't create a password, and instead it returns password =null or undefined. */
memberSchema.pre('save', async function (next) {
try {
if(!this.password===null|| this.password===undefined){
this.password = contrasenya
const salt = await bcrypt.genSalt(10)
hashpassword = await bcrypt.hash(this.password, salt)
}
const salt = await bcrypt.genSalt(10)
hashpassword = await bcrypt.hash(this.password, salt)
this.password = hashpassword
next()
}
catch (error) {
next(error)
}
})
memberSchema.post('save', async function (next) {
try {
console.log("userSchema.post done");
} catch (e) {
console.log(e);
}
})
//We set the export to a variable ‘city’ which was defined as 'Schema' on line6, and we exported as a mongoose model
module.exports = mongoose.model('members', memberSchema)
FRONT files:
the button component
import 'authGoogleAction' from './actions/loginActions'
const GoogleAuthButton = () => {
const dispatch = useDispatch();
const loggedIn = useSelector(state => state.members.loggedIn);
const singInButton = ()=> {
return(
<button type="button" onClick={authGoogleAction} className="google-button">
"Sign In"
</button>
)
}
return(
<div>
<div>{singInButton()}</div>
<p>User status logged in: {loggedIn? "You are connected":"You are NOT connected"}</p>
</div>
)
}
export {GoogleAuthButton}
loginActions
(...)
export function authGoogleAction() {
dispatch(
type: 'LOGIN_USER_SUCCESS',
payload: localStorage.get('user'),
}))
}
We're trying to integrate Passport authentication with out React app, and we're using React Router.
On the first submission of correct user credentials, the server receives the post, adds a session to our database, and seems to send a response, but the client doesn't update. The username and password show up in the url as a query string. Then when we resend the credentials without removing the query string from the url, the client is able to receive the response from the server.
In other words, if we don't refresh before submitting the login info again, it works.
This is the click handler that our form utilizes:
const handleClick = () => {
return axios.post('/login', { username, password })
.then(({ data }) => {
const { message } = data;
if (message === 'success') {
const { user } = data;
setUserId(user.id);
setUser(user);
}
setAuthStatus(message);
})
.catch(err => console.error(err));
};
This is our server route that is hit on every post request:
loginRouter.post('/', (req, res, next) => {
console.log('stop');
passport.authenticate('local', (err, user, info) => {
const { invalidPassword } = info || false;
if (err) {
return next(err); // will generate a 500 error
}
if (!user) {
return res.send({ message: 'invalidUser' });
}
if (invalidPassword) {
return res.send({ message: 'invalidPassword' });
}
req.login(user, loginErr => {
if (loginErr) {
return next(loginErr);
}
return res.send({ user, message: 'success' });
});
})(req, res, next);
});
This is our Passport Local Strategy that uses Sequelize:
passport.use(new LocalStrategy(
(username, password, cb) => {
User.findOne({ where: { username } })
.then((user) => {
if (!user) {
return cb(null, false);
}
if (validPassword(password, user.hash, user.salt)) {
return cb(null, user);
}
return cb(null, false, { invalidPassword: true });
})
.catch(err => {
cb(err);
});
},
));
Having trouble debugging this... We suspect the error is on the client side and may have to do with React-Router. We are using React-Router and Passport for the first time on this project.
Any help is appreciated!
Welp... All we were missing was event as a parameter in handleClick and event.preventDefault().
I have a router with the following route:
router.post('/login', async (req, res, next) => {
try {
console.log(req.body);
const { username, password } = req.body;
const identity = await userService.getUserInfo(username, password);
if (!identity.authenticated) {
return res.json({});
}
const requiredTenantId = process.env.TENANT_ID;
const tenant = identity.tenants.find((it) => it.id === requiredTenantId);
if (requiredTenantId && !tenant) {
return res.json({});
}
const userResponse = {
...identity,
token: jwt.sign(
identity,
envVars.getVar(envVars.variables.AUTH_TOKEN_SECRET),
{ expiresIn: '2h' }
)
};
return res.json(userResponse);
} catch (err) {
return next(err);
}
});
Which is basically an asynchronous function.
This is the working test sample:
const request = require('supertest');
const user = require('../../routes/user');
describe('Test user login path', () => {
test('If authorized, it should response with authorized JWT token', () => {
request(user).
post('api/user/login/').
send({
username: 'admin',
password: 'admin'
}).
expect(200);
});
});
If I add async before the function call and await before request user:
test('If authorized, it should response with authorized JWT token', async () => {
await request(user).
the test will fail with the following error:
connect ECONNREFUSED 127.0.0.1:80
Can somebody explain why it is like that? Because in the router I'm using the asynchronous route function.
That's because the supertest expects to be given an express application, not a router
You can create a test-purpose app, mount the user route:
const app = express();
app.use(bodyParser.json());
app.use("/api/user", user);
app.listen(3000);
and pass it to the request
await request(app)
.post("/api/user/login")
working example