I want to integrate sign in by google to an app that already has account signup and login.
I followed some youtube tutorial and I now have a working sign in by google working on my frontend. It returns a JWT upon successful log in. Decoding it gives me an object that contains an email, name, family name, pfp, and some other properties that I don't know what they are for.
What do I do with that ?
In my express server I have a register route
router.post("/register", async (req, res, next) => {
try {
// expects {email, password} in req.body
const { password, email } = req.body;
const user = await User.create(req.body);
const token = jwt.sign(
{ id: user.dataValues.id },
process.env.SESSION_SECRET,
{ expiresIn: 86400 }
);
res.json({
...user.dataValues,
token,
});
} catch (error) {
if (error.name === "SequelizeUniqueConstraintError") {
return res.status(401).json({ error: "Email already exists" });
} else if (error.name === "SequelizeValidationError") {
return res.status(401).json({ error: "Validation error" });
} else next(error);
}
});
Login route is similar.
The database I used was postgres with sequelize ORM, User.create(...)
basically just creates a user and stores the hashed password to verify later.
As you could see, if they use google auth it wont have a password while regular signup would. Do I just allow User.create to also create a user if password not given? Would that be secure? What is the correct way to go about this?
CodePudding user response:
A user who logs on to your app must
- either type their email address and password into your login form, then your app checks the password hash and creates the
token = jwt.sign(...)
. I would recommend that your JWT also contains the email address, preferably in the same format that Google's JWT uses. - or start a Google logon flow, then Google sends your app a JWT. During this flow, no password hash is looked up from your user database, but if the Google email address is not already in your database, it is a new user for whom you must insert a record into your database (only email address, no password).
The JWT should have an iss
claim that tells you whether it was issued by your app or by Google. In Google's case, the JWT is signed by Google, and in your /register
and /login
routes you must verify the signature with jwt.verify
using Google's public key (presumably this). (Actually, registration and login don't differ much if you use a third party authentication service like Google's.)
I assume that in both cases you store the JWT in a session cookie
res.cookie("jwt", token, {httpOnly: true});
and every subsequent request must repeat the signature verification of the JWT
try {
var jwt = jwt.verify(req.cookies.jwt, publicKey);
if (jwt.exp <= new Date().getTime() / 1000)
throw "expired";
// Token verification succeeded
} catch(e) {
// Token verification failed
}
(either with your own app's public key or with Google's, depending on the iss
). Only after successful verification does the request count as authenticated, and you can then retrieve the user record from your user store based on the email address.
The password (hash) in your use database is thus optional, but even users with a password could use Google for logon.