Getting email from google auth using vue, pinia, supabase - vue.js

wanting to add google auth to my vue app using supabase. How can i insert the users email from there google account into my users table once they sign up? my code to signup with email is below.
const handleSignup = async (credentials) => {
const { email, password, name } = credentials;
if(password.length < 6){
console.log("password way too short")
return errorMessageSignUp.value = "Password length is too short"
}
if(!validateEmail(email)){
return errorMessageSignUp.value = "Email is invalid"
}
loading.value = true
const {error} = await supabase.auth.signUp({
email,
password,
})
if(error){
loading.value = false
return errorMessageSignUp.value = error.message
}
await supabase.from("users").insert({
email,
name
})
const { data: newUser } = await supabase
.from("users")
.select()
.eq('email', email)
.single()
user.value = {
email: newUser.email,
name: newUser.name
}
loading.value = false
}
since the above takes in the email and password field and inserts it into the users table, im wanting to do the same when a user signups with google auth.
const signInWithGoogle = async () => {
await supabase.auth.signInWithOAuth({
provider: 'google',
})
}
// not sure on how to get email from google sign in/sign up

Instead of copying the email address on the front end, which could fail if the network is lost right after signing up, you can use database triggers to copy the data in the background when users sign up. This is more fail-tolerant and is the recommended way to implement such features in Supabase.
-- inserts a row into public.users
create function public.handle_new_user()
returns trigger
language plpgsql
security definer set search_path = public
as $$
begin
insert into public.profiles (id, email)
values (new.id, new.email);
return new;
end;
$$;
-- trigger the function every time a user is created
create trigger on_auth_user_created
after insert on auth.users
for each row execute procedure public.handle_new_user();
You can read more on the official guide here.

Related

Firebase updatePassword removes sign_in_second_factor phone property from token

I do a reautenticate with a user whom is already logged in as a Multifactor user
async reauthenticate(oldPassword: string): Promise<SignInEmailPassword> {
const user = firebase.auth().currentUser;
try {
if (user?.email) {
const cred = firebase.auth.EmailAuthProvider.credential(user.email, oldPassword);
await user.reauthenticateWithCredential(cred);
}
return { exception: '', token: '' };
} catch (reason) {
let phoneNumber = '****';
if ((reason as any).code === 'auth/multi-factor-auth-required') {
// The user is enrolled in MFA, must be verified
this.mfaResolver = (reason as any).resolver;
phoneNumber = (reason as any).resolver.hints[0].phoneNumber;
}
return { exception: 'auth/multi-factor-auth-required', phoneNumber };
}
}
I do the phone verification like
const phoneAuthProvider = new firebase.auth.PhoneAuthProvider();
const phoneOpts = {
multiFactorHint: this.mfaResolver.hints[0],
session: this.mfaResolver.session,
};
try {
this.verificationId = await phoneAuthProvider.verifyPhoneNumber(phoneOpts, recaptcha);
All good so far ( the recaptcha works with some other code, not mentioned here )
Then the actual SMS is verified, like:
const cred = firebase.auth.PhoneAuthProvider.credential(this.verificationId, phoneCode);
const multiFactorAssertion = firebase.auth.PhoneMultiFactorGenerator.assertion(cred);
const user = firebase.auth().currentUser;
try {
if (this.mfaResolver) {
await this.mfaResolver.resolveSignIn(multiFactorAssertion);
}
all good, and then finally
I can update the password with
const user = firebase.app().auth().currentUser;
if (user) {
await user.updatePassword(password);
}
If I console.log the token JUST before the updatePassword, I get my old token, with the
"sign_in_second_factor": "phone" property, but the token AFTER the updatePassword suddenly is without the sign_in_second_factor property, so basically it broke the token.
My solution is now to log out, and force the user to log back in ( again with MFA ), but an unnecessary step.
Is this avoidable,
to me it looks like a firebase bug, as it generates a valid token, WITHOUT a sign_in_second_factor being present, while it is a MFA firebase user.

API parse String for Login system

Helle How can I Parse a String to api side?
I am Trying to Make a Login System. I have the api side
import prisma from '../../lib/prisma'
export default async function handler(req, res) {
var user = 'admin'
var password = 'admin'
var email = 'admin#admin.com'
const db = await prisma.user.findMany({
where: {
username: user
}
})
}
But I Can‘t find a way To get all the var's (user, email, password) form the Page I call the api.

Is NextAuth Credentials safe?

I use next-auth Credentials (v3) to allow my users to register and sign in with good old email and password in my NextJS website. I use MongoDB as my database.
This is my [...nextauth].js file:
export default NextAuth({
session: {
jwt: true
},
providers: [
Providers.Credentials({
async authorize(credentials) {
await dbConnect();
// Check if a user with the email exists
const user = await UserModel.findOne({ email: credentials.email });
if (!user) throw new Error("Emailen is not in use");
// Check if the password is correct
const correctPassword = await bcrypt.compare(
credentials.password,
user.password
);
if (!correctPassword) throw new Error("Wrong password");
return {
userid: user._id,
email: user.email,
};
},
}),
],
callbacks: {
// Add userid to token
async jwt(token, user, account, profile, isNewUser) {
if (user) {
token.id = user.userid;
}
return token
},
// Add userid to session returned to front-end
async session(session, token) {
session.user.id = token.id;
return session
}
}
});
Before fetching data in my NextJS API endpoints, I check if the user is authenticated like this:
const session = await getSession({ req });
const user = await UserModel.findById(session?.user?.id);
if (!session || !user)
return res.status(400).json({ success: false });
But I'm worried that if a person gets the id of another user, they can just edit their JWT session.user.id and access any API endpoint pretending to be another user?
Is that true? Would the users be able to fake their id's in my code?
If so, what can I do to avoid that?

How do we hash a put request password?

Hi everyone am trying to hash my put request using bcrypt in my express-mongoose server
the put request
// updating a user
router.put('/:id', async (req, res) => {
const {error} = validate(req.body)
if (error) return res.status(400).send(error.details[0].message)
const user = await User.findByIdAndUpdate(req.params.id, {
$set : {
name: req.body.name,
email: req.body.email,
password: req.body.password
}
})
// hashing user passwords
const salt = await bcrypt.genSalt(10)
user.password = await bcrypt.hash(user.password, salt)
if (!user) return res.status(404).send('User with that id does not exist')
res.send(user)
})
All other functions inside the update request is working perfectly apart from hashing the updated password. As a newbie I need your help/ best approach recommendation in this.
Thanks in advance...
Solution 1: Easy Way
For your personal solution, without really modifying the code, it works like the following.
// updating a user
router.put('/:id', async (req, res) => {
const {error} = validate(req.body)
if (error) return res.status(400).send(error.details[0].message)
// Why not make the hash function here?
const salt = await bcrypt.genSalt(10)
const newPassword = await bcrypt.hash(req.body.password, salt)
const user = await User.findByIdAndUpdate(req.params.id, {
$set : {
name: req.body.name,
email: req.body.email,
password: newPassword
}
})
if (!user) return res.status(404).send('User with that id does not exist')
res.send(user)
})
You have a mistake in your user.password call. The findByIdAndUpdate method does not return an object that you can modify instantly. In above workaround, we simply move the function so that it hashes the new password first before updating your document.
Solution 2: My Own Style
For my personal solution, I'd go like this. Let's say that you have a userModel that stores the schema of your User entity. I will add a new middleware that will run every time the password changes.
/** your user schema code. **/
userSchema.pre('save', async function (next) {
// Only run the encryption if password is modified.
if (!this.isModified('password')) {
return next();
}
// Hash the password with BCRYPT Algorithm, with 12 characters of randomly generated salt.
this.password = await bcrypt.hash(this.password, 12);
next();
});
Next, we'll create a new dedicated route in order to handle password changes. I think it's better if we define a new route for it as passwords are sensitive data. Below is pseudocode, don't instantly copy and paste it, it wouldn't work.
const user = await User.findById(...);
user.password = req.body.password;
await user.save({ validateBeforeSave: true });
Remember that save middleware runs every time after the save command is run.
Further reading about Mongoose's middlewares here.

AdonisJS catch database insert errors with api-only while using ORM

Is there a way to catch database insert errors i.e. duplicate entry when using the Adonis ORM in api-only mode.
In the example below, if the username is a duplicate, it just sends a 500 internal server error and dumps a full html page of the error to the client.
Even if I don't know what the error is, I would at least like to be able to catch the error and send a more usable json object like
{error: "Unable to insert user"}
Here is some example code
const User = use('App/Models/User')
class UserController {
async register({ request }) {
const { username, email, password, first_name, last_name } = request.all()
const user = new User()
user.fill({
username,
email,
password,
first_name,
last_name
})
await user.save()
return user
}
}
Partly Solved:
I have partly solved this issue with the following code, but I feel as though there must be a better / built in way to achieve this.
const User = use('App/Models/User')
class UserController {
async saveData(object, errorMessage){
try{
await object.save()
return object
}
catch(err) {
return {error:`${errorMessage}`}
}
}
async register({ request, response }) {
const { username, email, password, first_name, last_name } = request.all()
const user = new User()
user.fill({
username,
email,
password,
first_name,
last_name
})
return this.saveData(user, "Unable to save user")
}
}
Try & catch is what you're looking for. You can also use global exceptions.
Regarding your duplicate error, you should also use the AdonisJs Validator to make sure you won't get this errors.
So before you save your model, check that the given user is unique for example.
So you would have something like this
async register({ request, response }) {
const { username, email, password, first_name, last_name } = request.all()
const rules = {
username: 'required|unqiue:username'
};
const validation = await validate(request.all(), rules);
if (validation.fails()) {
response.status(500).send(validation.messages());
}
const user = new User()
user.fill({
username,
email,
password,
first_name,
last_name
})
await user.save();
return user;
}