In a registration form I have three fields
Username
email id
password
When the user registers I need to verify whether the username is already taken or not . I am sending email and password for authentication and updating the profile with username . How can I check the username taken or not ?
firebase.auth().createUserWithEmailAndPassword(this.state.email, this.state.password).then(createdUser => {
console.log(createdUser);
createdUser.user.updateProfile({
username: this.state.username
})
First of all, note that there is no username property for a User. Consequently, passing an object with a username property to the updateProfile() method will not work. You need to pass an object with the displayName and photoURL properties.
If you want to associate a username to your user, what you can very well do (and which is very common) is to have, in the Firestore database, a collection which contains a document for each user. You then store this username value in this document.
Then, to check the "username is not taken", you can query the collection before creating the user, as follows:
var db = firebase.firestore();
var usersRef = db.collection('users');
usersRef.where('username', '==', this.state.username).get()
.then(snapshot => {
if (snapshot.empty) {
return firebase.auth().createUserWithEmailAndPassword(this.state.email, this.state.password);
} else {
throw new Error('username already taken');
}
})
.then(createdUser => {
console.log(createdUser);
//Create the user doc in the users collection
db.collection('users').doc(createdUser.user.uid).set({username: this.state.username});
})
.catch(err => {
console.log('Error: ', err);
});
Hi you can have a onChange event on username field which calls the api to know if the username already exists or not. And then in onSubmit you can validate if username is not taken you can submit the call.
Related
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.
When a new user registers the web application a verification email is sent to him. I prevent new users to log in before verification.
Meanwhile if the verification link expires and the user forgets the password he will click the reset password link and will receive an email.
So I think that I should handle reset password action together with verification at once. Otherwise user will not be able to login even after changing the password.
function handleResetPassword(auth, actionCode) {
auth.verifyPasswordResetCode(actionCode)
.then(function (email) {
// Showing the reset screen and ask the user for
// the new password.
}).catch(function (error) {
//
});
};
When user saves the new password:
function saveNewPassword() {
auth.confirmPasswordReset(actionCode, vm.form.password).then(function (resp) {
// Password reset has been confirmed and new password updated.
// Now auto sign in user
auth.signInWithEmailAndPassword(vm.email, vm.form.password).catch(function (error) {
// Handle Errors here.
});
firebase.auth().onAuthStateChanged(function (user) {
if (user) {
// user signed in.
// check whether the user is verified
// if not set true
user.updateProfile({ emailVerified: true })
}
});
}).catch(function (error) {
//
});
}
But the code below doesn't work as I expected as it has no affect. I can change other user data (e.g. displayName) but not (emailVerified). It only works with firebase email verification.
user.updateProfile({ emailVerified: true })
What is the recommended approach for this type of user scenario ?
You can't update emailVerified from the client, otherwise any unverified user would be able to do that without enforcing actual ownership of the email.
You would need to do it with the Admin SDK using an HTTP endpoint (you can use Firebase Functions for that too). However, you need to ensure that the password reset code succeeded. So in this case you need to run your code on the server. Here is how it would work:
var firebase = require('firebase');
var admin = require('firebase-admin');
// Initialize the client and admin instances.
// firebase.initializeApp(clientConfig);
// admin.initializeApp(adminConfig);
// Send the reset code and the new password to your backend.
var email = null;
// Get email corresponding to code.
firebase.auth().checkActionCode(actionCode)
.then(function(info) {
email = info.email;
// Confirm password reset.
firebase.auth().confirmPasswordReset(actionCode, password)
});
.then(function() {
// Get uid of user with corresponding email.
return admin.auth().getUserByEmail(email);
}).then(function(userRecord) {
// Password reset succeeded. Email can be verified as the user
// must have received the code via their email confirming
// ownership.
return admin.auth().updateUser(userRecord.uid, {emailVerified: true});
});
The Authorization module in Firebase only allows me to store a user's email and password; but I want to store more information, like: name, phone number, list of games they own, etc. How do I do that in firebase?
Choosing Firebase for data storage is good choice in my view. Because, it is easy to use and less expensive.
Coming to the problem, you can't set additional data to the authentication table in Firebase console.
It just shows email and unique user id and doesn't show even password used for registration.
One of the easy way of storing user information in Firebase is as follows.
After success of login or signup of user, you will get user's unique id.
function(error, userData) {
if (error) {
console.log("Error creating user:", error);
} else {
console.log("Successfully created user account with uid:", userData.uid);
}
With that user id, you can create an object in Firebase database.
function(error, userData) {
if (error) {
console.log("Error creating user:", error);
} else {
var userId = userData.uid;
var ref = new Firebase('https://docs-examples.firebaseio.com/web/data');
var userRef = ref.child('users/' + userId);
userRef.set({
email: "userEmail",
name: "userName",
phoneNumber: "userPhoneNumber",
password: "userPassword",
interestedGames: {
"game1": true,
"game2": true,
"game3": true
}
});
}
You can retrieve the data of the user using childRef as I shown above,
that you can get when user logs in.
I have created a simple login app using react native that let's users signup, login, and logout. my signup function takes a username that is then used in the createUser callback to generate a db entry with the uid as the key, and the username entered as a value. The answer in this post is the structure I followed - How do you include a username when storing email and password using Firebase (BaaS) in an Android app?
After the user is logged in, I'd like to get the username and display it but I'm having trouble figuring this out.
This is the code I currently have to attempt and do it:
var ref = new Firebase("https://myreactapp.firebaseio.com");
module.exports = React.createClass({
getInitialState: function() {
var authData = ref.getAuth();
var user = ref.child("users/" + authData.uid + "/username");
return {
username: user
};
},
This is how the code looks when I signup and the structure of my db.
var self = this;
let ref = new Firebase("https://myreactapp.firebaseio.com");
ref.createUser({
email : this.state.email,
password : this.state.password
}, function(error, authData) {
if (error) {
return this.setState({errorMessage: 'Error creating user'});
} else {
ref.child("users").child(authData.uid).set({
username: self.state.username
});
console.log("Successfully created user account with uid:", authData.uid);
ToastAndroid.show('Account Created', ToastAndroid.SHORT)
return self.props.navigator.pop();
}
});
----------------Not actual code-------------------------------------------------
DB
+users
--<uid>
-username -> value
--<uid>
-username -> value
I try to login and get an error of maximum call stack exceeded, but I have a feeling I'm going at this the wrong way. I've looked online, but everything I found was for retrieving data that is either being added, changed or deleted. All I want is to get this username once.
I'm very new to the MEAN stack, and this might seem to be very naive or wrong approach, but I want to ask that when we authenticate using passport-facebook strategy, using the following code:
var FacebookStrategy = require('passport-facebook').Strategy;
var User = require('../models/user');
var fbConfig = require('../fb.js');
module.exports = function(passport) {
passport.use('facebook', new FacebookStrategy({
clientID : fbConfig.appID,
clientSecret : fbConfig.appSecret,
callbackURL : fbConfig.callbackUrl
},
// facebook will send back the tokens and profile
function(access_token, refresh_token, profile, done) {
console.log('profile', profile);
// asynchronous
process.nextTick(function() {
// find the user in the database based on their facebook id
User.findOne({ 'id' : profile.id }, function(err, user) {
// if there is an error, stop everything and return that
// ie an error connecting to the database
if (err)
return done(err);
// if the user is found, then log them in
if (user) {
return done(null, user); // user found, return that user
} else {
// if there is no user found with that facebook id, create them
var newUser = new User();
// set all of the facebook information in our user model
newUser.fb.id = profile.id; // set the users facebook id
newUser.fb.access_token = access_token; // we will save the token that facebook provides to the user
newUser.fb.firstName = profile.name.givenName;
newUser.fb.lastName = profile.name.familyName; // look at the passport user profile to see how names are returned
//newUser.fb.email = profile.emails[0].value; // facebook can return multiple emails so we'll take the first
// save our user to the database
newUser.save(function(err) {
if (err)
throw err;
// if successful, return the new user
return done(null, newUser);
});
}
});
});
}));
};
I don't need to store the user information in any data store. I want to store the token only for the time the user is logged into my web application, basically I don't have the need to use Mongo, because all the data that will be displayed in the web application will come from Facebook api, for example the posts for a profile, the number of likes on a particular posts etc. I don't need to have a backend as such, because if I store the data in any data store such as Mongo, the next time the user login then the data will be stale (in a way the Facebook api is kind of my backend), and I also want that the updates for information on any posts done on Facebook should be updated realtime on my web application for e.g. if someone likes a post on the actual Facebook page the number of likes on my web application should also be updated in realtime, so it seems unnecessary to first bring the data from the Facebook SDK and then store it in Mongo, why not just give it to the controller and from there the view can present the data. If my approach is wrong please do correct me.
So basically every time the user logs in an access token is created and used for that session, when the user logs out the access token is destroyed and so completely eliminates the need for storing the token and any data that is brought in using the Facebook SDK.
Replace the function call
User.findOne({ 'id' : profile.id }, function(err, user) {
With facebook sdk authentication call and return the user object when it's validated.
return done(null, user);
Please refer...
https://github.com/jaredhanson/passport-facebook
you need to create a new user template in the model folder. I have created the following: user.js
var facebook = module.exports.facebook = {
id : String,
token : String,
email : String,
name : String
}
and then change the passport.serializeUser and passport.deserializeUser functions.
passport.serializeUser(function(user, done) {
done(null, user.facebook.id);
});
// used to deserialize the user
//passport.deserializeUser(function(id, done) {
passport.deserializeUser(function(id, done) {
done(null, { id: User.facebook.id, token: User.facebook.token, name: User.facebook.name, email: User.facebook.email})
});
then the function: process.nextTick(function() {} replace the content by this code :
var newUser = User;
// set all of the facebook information in our user model
newUser.facebook.id = profile.id; // set the users facebook id
newUser.facebook.token = token; // we will save the token that facebook provides to the user
newUser.facebook.name = profile.name.givenName + ' ' + profile.name.familyName; // look at the passport user profile to see how names are returned
newUser.facebook.email = profile.emails[0].value; // facebook can return multiple emails so we'll take the first
return done(null, newUser);
add the line profileFields: ['id', 'displayName', 'photos', 'emails', 'name'] in function passport.use(new FacebookStrategy({}
change the profile.ejs file by removing the local information div and changing the properties <% = user.facebook.id%> to <% = user.id%> and so on in the others.