import Auth from '#aws-amplify/auth';
await Auth.signUp({
username,
password,
attributes: {email, phone_number: phoneNumber}
})
assume 'phoneNumber' is a user-dependent input.
many (most) inputs will cause failure.
What is the most practical method for validation of 'phoneNumber' prior to Auth.signUp ?
Additionally, why does failure manifest as such in React Native?:
Related
I have an email input and i want to validate that the user entered a specific email "abcd#fg.com" and if not to show specific error message "This email is not in our database". I am using zod validation to do that, but how can it be done?
const LoginSchema = z.object({
email: z
.string()
.min(1, { message: "This field has to be filled." })
.email("This is not a valid email.")
})
});
I can show how to do this, but I don't think this should be done (more later).
You can use refine to check if the string is exactly some expected value. For example:
const LoginSchema = z.object({
email: z
.string()
.min(1, { message: "This field has to be filled." })
.email("This is not a valid email.")
.refine((e) => e === "abcd#fg.com", "This email is not in our database")
});
Then, later if you were going to pull down emails so you can write a validation on the frontend you would use an async refinement with parseAsync like:
const login2 = z.object({
email: z
.string()
.min(1, { message: "This field has to be filled." })
.email("This is not a valid email.")
.refine(async (e) => {
const emails = await fetchEmails();
return emails.includes(e);
}, "This email is not in our database")
});
Opinion Warning
I would not recommend doing this for 2 reasons:
The number of emails is likely to be very large if you have any meaningful number of users. Pulling all of those down just to make this check would be a pretty big waste of resources and time.
Security wise, sharing emails of all your users publicly over the API strikes me as a dangerous thing to do. Anyone would hit that API to get real email addresses for all of your users.
I would recommend not validating this as part of the data validation. This validation should happen on the backend and return a 4XX error response when logging in.
Edit
A comment on this post mentioned that you could instead provide an API to validate an email address. This could be safely used from an async refinement and avoids the issues described above.
That would look like:
const login2 = z.object({
email: z
.string()
.min(1, { message: "This field has to be filled." })
.email("This is not a valid email.")
.refine(async (e) => {
// Where checkIfEmailIsValid makes a request to the backend
// to see if the email is valid.
return await checkIfEmailIsValid(e);
}, "This email is not in our database")
});
Currently, a user is able to login in and sign up for my application no problem. I've then added a "Link your twitter user to account" button which when clicked takes the user to '/auth/twitter'. This then kicks off passport-twitter and the oAuth process begins.
Right now, I'm using passport-twitter as the package for twitter oAuth. This process works. I'm able to get the user successfully authenticated. Here is the code.
However two problems: I don't see a way to 1) keep the user signed into Twitter so they don't have to keep doing this flow of reconnecting their twitter every time they want to push content to it from my app. and 2) associate the Twitter user and the signed in user to my application. Long term, I plan to add other social media accounts, so the user will have multiple social media linked. Twitter will be just one.
Problem #2: I wasn't able to do an axios.get call from my redux store or from the front end to '/auth/twitter/' otherwise I could then just get the information back from the call and then post it to the user's table (right?). So, instead I'm accessing '/auth/twitter' from an tag in the front end to kick off the flow.
passport.use(
new TwitterStrategy(
{
consumerKey: "XXX",
consumerSecret: "XXX",
callbackURL: "http://localhost:8080/auth/twitter/callback",
// callbackURL: "http://www.localhost:8080/home",
includeEmail: true,
},
async(accessToken, refreshToken, profile, cb) => {
console.log('got the prodile')
const twitterIDforOAuth = profile.id
const { id, username } = profile;
let theuser = await User.findOne({
where: {
twitterID: id
}
})
if(theuser){
console.log('FOUND USER', '\n', theuser)
} else {
try {
console.log('NO USER FOUND')
var passwordUser = (Math.random() + 1).toString(36).substring(7);
console.log('CREATING USER')
theuser = await Promise.all([
User.create({
twitterID: id,
username : username,
password: passwordUser
})
])
console.log('USER CREATED');
} catch (error) {
console.log(error);
}
}
//this callback calls the auth/callback url to kick off the redirect process
// need to send username and password to /auth/signup
return cb(null, {username: username, password: passwordUser})
//Line below sends too much data that is irrelevant for the user... lets review it?
// return cb(null, {username: twitterIDforOAuth})
}
)
);
app.get('/auth/twitter', passport.authenticate("twitter"));
app.get(
"/auth/twitter/callback",
passport.authenticate("twitter", {
failureRedirect: "/login",
failureMessage: true,
session: false
}),
async (req, res) => {
var user = req.user;
console.log(user.username, user.password);
//GET USERNAME AND PASSWORD
var username = user.username;
var password = user.password;
///they need to login the app
//auth/login
res.redirect('/AccountSettings')
}
);
The user is being redirected to /AccountSettings while they go through this flow, so I know that the user is 100% authenticated and signed in with Twitter (otherwise they'd be pushed to /login, which isn't happen).
Most people in this flow create a user in their database using the information returned from Twitter.
However, I'm trying to link this information to the signed in user, and keep them signed into Twitter so the user doesn't need to keep reconnecting their Twitter account (at least not often). (With access to their Twitter account, my plan is to allow them to push content to it)
Currently I'm hitting the '/auth/twitter' route with an tag which's href takes it to '/auth/twitter'. Is this the right way about it or is this approach causing my linkage issue?
What are people's recommendation for this issue? Whats the right way to approach linking social media accounts to a signed in user's account?
I'm using Express, Redux, React, Postgres, and passport-twitter
SOLUTION: How to passing data in TwitterStrategy, PassportJS?
had to create a state object outside the /auth/twitter route and then added a id param to the /auth/twitter route so the full route was /auth/twitter/:id
once I got the id I saved it to a state route outside the route in the server file that was accessible to the callback function later in the proces.
I'm facing an issue updating a password for a supabase user on a BlitzJs (NextJs) project.
Basically, I have a reset password method that works perfectly. First I send an email with a reset link, that opens a page where the user can update his password like so:
const { error, data } = await supabase.auth.api.updateUser(token, { password: password.trim() })
the token being the one in the url, provided in the email link.
So far, so good, but when I try to update the password for a logged in user, using the exact same method supabase.auth.api.updateUser, it fails to find the user;
The difference is the token is the session.access_token
So I've tried to use the supabase.auth.api.updateUserById method, but it gives me another error: { message: 'User not allowed', status: 401 }
Any ideas? I feel the supabase docs about this is not very clear, and probably outdated as it doesn't show all the available methods :/
Update password for authenticated user.
const { user, error } = await supabase.auth.update({password: 'new password'})
For more informations check: Supabase references
How secure is the context in react, I want to created a user from front end and set his indicial status to demo . later on when the user make a payment his status will change , bottom line is how secure this logic is could someone come and modify the initial set status to 'premium' ? so he could skip the payment part ?
const Signup = async (email: string, password: string, userType: string) => {
await createUserWithEmailAndPassword(auth, email, password)
.then((userCredential) => {
setDoc(doc(db, 'Data', userCredential.user.uid), {
user: userType,
verifiedEmail: false,
status: 'demo',
createdAt: Timestamp.now(),
});
As a rule of thumb and especially for single page applications which are rendered on the client side: Data from and (with)in clients can't and shouldn't be trusted as a security measurement.
So consider the context as "not secure" and always rely on proper permission management on the server side - so the worst thing which can happen is that your client may see the "premium" menus, but can't get anything out of it since the server denies any action.
I build an app using aws-amplify that allows login with Cognito users. However, Auth.forgotPassword seems to be sending SMS to mobile device instead of EMAIL. How can I change the behavior such that it sends an email?
Here are related code:
Auth.forgotPassword(this.state.username)
.then(data => this.setState({instruction: 'An email has been sent to your email with a temporary password.', usernameError: false, passwordError: false}))
.catch(err => this.setState({instruction: err.message, usernameError: false, passwordError: false}));
You can configure what you need to verify when forgotPassword API is triggered in the AWS Cognito Console.
Amazon Cognito > Manage User Pool > Choose your pool > General Settings > MFA and verifications > Which attributes do you want to verify?
Also when you trigger the ForgotPassword API you get CodeDeliveryDetails Object in response
const result = await Auth.forgotPassword(username);
console.log(result);
CodeDeliveryDetails: {
"AttributeName": "email",
"DeliveryMedium": "EMAIL",
"Destination": "n***#g***.com"
}
From the result, you get on which medium the code has been delivered and accordingly notify the user in the app.