This question already has answers here:
Username authentication instead of email
(4 answers)
Closed 3 years ago.
Hello Im doing an app in angular, firebase and ionic. I have used a login starter in my app and I want my app to register with a username, email and password. I need the username for later in the app to put Hello [username]. I have the option to register firebase with the property .createUserWithEmailAndPassword(email, password)this property only allows the registration of email and password, how can I add a parameter for username? I would appreciate detailed explanation I am a noob.
I have the code divided into a page and a service and the html part.
-HTML PAGE
<ion-item lines="none">
<ion-input class="placeholdertext inputField" type="text" placeholder="Username" [(ngModel)]="name" autofocus="true" padding-start></ion-input>
</ion-item>
<ion-item lines="none">
<ion-input class="placeholdertext inputField" type="text" placeholder="nombre#dominio.com" [(ngModel)]="email" autofocus="true" padding-start></ion-input>
</ion-item>
<ion-item lines="none">
<ion-input class="placeholdertext inputField" type="password" placeholder="ContraseƱa" [(ngModel)]="password" padding-start clearInput></ion-input>
</ion-item>
-REGISTER PAGE TS
register() {
this.spinner = true;
this.disabled = true;
this.auth
.signupUser(this.email, this.password)
.then(res => {
console.log(res);
this.auth.writeNewUser(this.email, res.user.uid)
.then(response => {
this.auth.getUser(res.user.uid).then(user => {
this.spinner = false;
this.disabled = false;
this.route.navigate(['approved']);
console.log(this.email, this.password );
});
})
})
-FINALLY THE AUTH SERVICE
signupUser(email: string, password: string): Promise<any> {
return this.afAuth.auth
.createUserWithEmailAndPassword(email, password)//In this part it does not let me add another parameter
}
writeNewUser( email: string, uid: string): Promise<any> {
console.log(name, uid, email)
return this.db
.collection('drivers')
.doc(uid)
.set({
email: email,
available: false,
approved: false
});
}
loginUser( email: string, password: string): Promise<any> {
return this.afAuth.auth.signInAndRetrieveDataWithEmailAndPassword( email, password);
}
signupUser(email: string, password: string): Promise<any> {
return this.afAuth.auth
.createUserWithEmailAndPassword(email, password)
}
As I said before I want both in the registration and login can add another password to enter a username, then when the user login start the app with your username and put hello [username]. Adjoint where this property comes out. createuserwithemailandpassword. https://firebase.google.com/docs/auth/web/manage-users?hl=en-419
I appreciate any help. I also speak Spanish
Firebase Authentication doesn't support the use of a username to identify the user. The user must provide an email address to validate their identity. If you want to assign a username later, that's fine, but they still wont' be able to sign in with it. They will always have to use their email address and password.
Related
I'm having trouble connecting my Devise Token Auth with a token I get back from google in react.
I'm using this package for the button:
https://www.npmjs.com/package/react-google-login
This is the auth I'm trying to set up:
https://github.com/lynndylanhurley/devise_token_auth/blob/master/docs/config/omniauth.md
I'm getting a response from google with the react button but I have no idea how that information has to translate to go back to the devise auth.
Information online is severely lacking between these 2 technologies. What it comes down to is how to translate this ruby tag into react:
<%= link_to "Sign in with Google", user_google_oauth2_omniauth_authorize_path, method: :post %>
I know this is old but here are my 2 cents.
I have used this gem OmniAuth Google OAuth2. The information is pretty clear. In my project, I manage my token using JWT while still storing the access and refresh tokens from Google.
Backend
# config/initializers/devise.rb
config.omniauth :google_oauth2,
ENV['GOOGLE_CLIENT_ID'],
ENV['GOOGLE_CLIENT_SECRET'],
{ scope: "userinfo.email, userinfo.profile",
prompt: 'select_account',
image_aspect_ratio: 'square',
provider_ignores_state: true,
}
# controllers/users/omniauth_callbacks_controller.rb
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
def google_oauth2
#user = User.from_omniauth(request.env['omniauth.auth'])
if #user.persisted?
# My personal token
token = issue_token(#user)
render json: { success: true,
user: #user,
token: token,
google_token: #user.access_token,
message: "Logged in successfully." }
else
render json: { success: false,
error: #user.errors.full_messages.join("\n"),
message: 'Google sign in unsuccessful.' }
end
end
def failure
set_flash_message! :alert, :failure, kind: OmniAuth::Utils.camelize(failed_strategy.name), reason: failure_message
render json: { success: false, message: 'Google authentication failed.', reason: failure_message, kind: OmniAuth::Utils.camelize(failed_strategy.name) }
end
private
end
# In User.rb
def self.from_omniauth(auth)
user = User.where(email: auth.info.email).first
if user
user = User.update(id: user.id,
refresh_token: auth.credentials.refresh_token,
access_token: auth.credentials.token,
uid: auth.uid,
)
else
# Create a username from names, append incremental if username already exists
username ||= auth.info.first_name + auth.info.last_name
username = username.delete('^a-zA-Z0-9_').downcase
num = 1
until User.find_by(username: username).nil?
username = "#{username}#{num}"
num += 1
end
user = User.create(email: auth.info.email,
uid: auth.uid,
refresh_token: auth.credentials.refresh_token,
access_token: auth.credentials.token,
provider: auth.provider,
password: Devise.friendly_token[0, 20],
firstname: auth.info.first_name,
lastname: auth.info.last_name,
username: username,
)
end
user
end
# routes.rb
# User Routes: Devise
devise_for :users,
path_names: {
sign_in: 'login',
sign_out: 'logout',
# sign_up: 'register'
},
controllers: {
sessions: 'users/sessions',
registrations: 'users/registrations',
omniauth_callbacks: 'users/omniauth_callbacks'
}
Above routes translations
user_google_oauth2_omniauth_authorize_path GET|POST /api/users/auth/google_oauth2(.:format)
users/omniauth_callbacks#passthru
user_google_oauth2_omniauth_callback_path GET|POST /api/users/auth/google_oauth2/callback(.:format)
users/omniauth_callbacks#google_oauth2
Here is the front end
<!-- index.html -->
<head>
<script src="https://apis.google.com/js/platform.js?onload=init" async defer></script>
</head>
Do not worry about defining the gapi function, it is loaded script in the above
// RegisterContent.js
const RegisterContent = function RegisterContent() {
function handleResponse(response) {
// Save user to redux store and all the tokens to cookies
}
// callback
function signInCallback(authResult) {
if (authResult.code) {
const params = { code: authResult.code }
const path = "localhost:3000/api/users/auth/google_oauth2/callback";
// This just handdles posting with axios
postResource(path, params, handleResponse);
}
}
// This will prompt opening the google window and returns a callback upon success
const googleHandler = () => {
googleAuth.grantOfflineAccess().then(signInCallback);
};
useEffect(() => {
// Initialize the GoogleAuth object
gapi.load("auth2", function foo() {
const auth = gapi.auth2.init({
client_id: process.env.REACT_APP_GOOGLE_CLIENT_ID,
scope: "email profile",
});
setGoogleAuth(auth);
console.log("Init");
});
}, []);
return (
<Button onclick={googleHandler}>
Continue with Google
</Button>
);
}
A few resources to help Google Sign-In JavaScript client reference,
How to integrate Google API into your React app and that's it.
It's in the end just a post request to that endpoint but I have encountered the same problems as you are.
What you need to do is to create a form like this:
<form action="<%=user_google_oauth2_omniauth_authorize_path %>" method="post">
<input type="hidden" name="authenticity_token" value="XX">
<button type="submit">Connect Google</button>
</form>
My trials failed when I haven't passed the auth token or added a "skip_before_action :verify_autneticity_token" to the callback controller. You need to fill the correct authenticity token, then it works.
Authenticity token information can be added to your html page's head section, via <%= csrf_meta_tags %>. Then you will need to parse the dom for the meta fields to fill them correctly.
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.
I am new to firebase and have managed to successfully setup an authentication with email/ password based off what I have managed to gather from the documentation/ examples online. I've encountered some strange behaviour on register though. First of all here is my firebase auth code that sits in a React component function:
class SignupComponentInner extends Component {
toggleSignupLayoverAction(event){
this.props.toggleSignupLayover("false")
}
signUp(e) {
e.preventDefault();
var firstName = $('.signup-first-name').val();
var lastName = $('.signup-last-name').val();
var userName = $('.signup-user-name').val();
var password = $('.signup-user-password').val();
var email = $('.signup-email').val();
var auth = firebase.auth();
const promise = auth.createUserWithEmailAndPassword(email,password).then(function(user) {
var user = firebase.auth().currentUser;
user.updateProfile({
displayName: userName,
}).then(function() {
// Update successful.
// new db code here
firebase.database().ref('users/' + user.uid).set({
firstName: firstName,
lastName: lastName,
userName: userName
})
// end new db code here
}, function(error) {
// An error happened.
});
}, function(error) {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
// [START_EXCLUDE]
if (errorCode == 'auth/weak-password') {
alert('The password is too weak.');
} else {
console.error(error);
}
// [END_EXCLUDE]
});
promise.catch(e => console.log(e.message));
firebase.auth().onAuthStateChanged(firebaseUser => {
if(firebaseUser) {
console.log("logged in");
var sendUserId = firebaseUser.uid;
this.props.logUserIn(sendUserId)
} else {
console.log("not logged in")
}
});
}
render() {
return (
<div onClick={this.toggleSignupLayoverAction.bind(this)} className="signup-cont-par">
<div className="signup-component-inner">
<div className="signup-component-content" onClick={cancelBubble.bind(this)}>
<h2>Sign up today!</h2>
<form className="signup-form-elem">
<input placeholder="First Name" className="signup-first-name" type="text"></input>
<input placeholder="Last Name" className="signup-last-name" type="text"></input>
<input placeholder="Username" className="signup-user-name" type="text"></input>
<input placeholder="Password" className="signup-user-password" type="password"></input>
<input placeholder="Email Address" className="signup-email" type="text"></input>
<button onClick={this.signUp.bind(this)}>Sign Up</button>
</form>
</div>
</div>
</div>
)
}
}
So the registration part works exactly as it should but its the login part here that is causing issues:
firebase.auth().onAuthStateChanged(firebaseUser => {
if(firebaseUser) {
console.log("logged in");
var sendUserId = firebaseUser.uid;
this.props.logUserIn(sendUserId)
} else {
console.log("not logged in")
}
});
It's basically executing twice as im getting console.log "logged in" twice on register. Not sure why that is?
The other issue is the function that it is calling from the props this.props.logUserIn(sendUserId) This function basically hides a "create account" CTA and replaces it with a hello {{username}}. The username updates on register but very strangely it will update to whatever username I registered on the previous register! Here is the logUserIn function if it helps:
logUserIn(userId) {
var db = firebase.database();
var ref = db.ref('/users/' + userId);
console.log(userId);
ref.once('value').then((snapshot) => {
var userObject = snapshot.val();
var loggedUserName = userObject.userName;
this.setState({
LoggedInUsername:loggedUserName
})
});
this.setState({
loggedInState:true,
LoggedInId:userId,
signingUp:"inactive"
})
},
Here loggedUserNameis a state that is passed down to the main component to show the username that has just been registered (the one that is incorrectly showing the previous registered person when it should be showing the latest). Not sure where I have gone wrong.
Firebase maintains persistent connections with their servers so if you registered once, Firebase detects your browser and machine to be logged in for that newly created user. So, if you close the browser and then come back to your project on the SAME browser, Firebase still thinks you are logged in and hence, the onAuthStateChanged event handler is called.
Try it out for yourself and see what happens when you open up 2 different browsers.
To complete the whole authentication system, you need to have a logout function that will tell Firebase that this user has logged out (https://firebase.google.com/docs/auth/web/password-auth#next_steps)
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 new to firebase, and I'm trying to add a Date Of Birth field to a form and save it to Firebase.
The input field in the form looks like this:
<label for="birthdate">Date of Birth</label>
<input type="date" id="birthdate" name="birthdate"
ng-model="user.birthdate" ng-required="true" placeholder="Last Name">
<p class="error validationerror"
ng-show="myform.birthdate.$invalid && myform.birthdate.$touched">
Birthdate is required</p>
Following a lynda.com tutorial, a working register function was created like this:
register : function(user) {
return simpleLogin.$createUser(user.email, user.password)
.then(function(regUser){
var ref = new Firebase(FIREBASE_URL + 'users');
var firebaseUsers = $firebase(ref);
var userInfo = {
date: Firebase.ServerValue.TIMESTAMP,
regUser: regUser.uid,
firstname: user.firstname,
lastname: user.lastname,
email: user.email
}
firebaseUsers.$set(regUser.uid, userInfo);
}); //add user
}, //register
I tried to simply add another birthdate: user.birthdate key:value pair to the end after email: user.email but that didn't work.
register : function(user) {
return simpleLogin.$createUser(user.email, user.password)
.then(function(regUser){
var ref = new Firebase(FIREBASE_URL + 'users');
var firebaseUsers = $firebase(ref);
var userInfo = {
date: Firebase.ServerValue.TIMESTAMP,
regUser: regUser.uid,
firstname: user.firstname,
lastname: user.lastname,
email: user.email,
birthdate: user.birthdate
}
firebaseUsers.$set(regUser.uid, userInfo);
}); //add user
}, //register
Nothing gets added to firebase for the birthdate.
If I do console.log("user.birthdate: "+ user.birthdate); right after var userInfo I can see the date that was chosen in the date picker... so I know its getting from the form into that register function.
I'm guessing that simpleLogin can only have firstname, lastname, and email?
A few helpful notes:
Firebase Simple Login has been deprecated by Firebase, in favor of the native authentication methods built into each of the Firebase client libraries. That said, it will continue to work.
Both Firebase Simple Login, and the native Firebase authentication, are merely delegated authentication services. That is, they only store credentials to make authentication easier in your app, but they do not store arbitrary user data. Your Firebase is the best play for that.
In the above example, writing to new Firebase(.../users) is writing to Firebase, not the authentication service, and you can write any arbitrary data of your choosing there. However, check the type of the birthdate that you're writing. Firebase leaf values can be of type string, number, boolean, or null - but it is likely that your datepicker might be returning an Object that just happens to toString() correctly.