Firebase permissions: Sign up with username and password - ios

I'd like to have my users sign up with a unique username and password (rather than email + password). I have everything working where I:
Sign up
Check if the provided username already exists
If not, then use FIRAuth.auth()?.createUserWithEmail and store the username in the db with the email, e.g.
users
QZqFzWxpdMfc0xmyIq5IDAr1bzr2
credentials
email: "myemail#gmail.com"
username: "MyUsername"
RJasdfasfasdad3dadaewdsdkdq3dk
credentials
email: "another#gmail.com"
username: ""Another
Sign in
Query the db to get User associated with the username and use that to get the email address and use FIRAuth.auth()?.signIn(withEmail: withEmail to log in
While this approach work, I'm wondering how this would work with Firebase permissions?
In order to get the email address associated with the username, I'm going to have to let all users access my email address / username data, e.g.
{
"rules": {
".read": true,
".write": "auth != null"
}
}
Does this mean that a 'hacker' could get the email addresses of all the users who have registered with my app? If so, is there a way to do this securely?

Well to answer your question if anyone can get data if the rules are set to true: yes, I can query everything from every user when I am registered. Do not do this unless you are testing. Write database rules: only Firebase Database can access every data and check the unique name for you. Simple example:
{
"allusernames": {
".read": false,
".write": "!data.exists() && newData.exists()"
}
}
When you get an error in your code, with other words the write failed, you know the username is taken.

Related

Firebase verifying email while being logged in

I have the following logic in my iOS app:
User registers
Firebase sends an email confirmation
Returns to login screen
Now if the user logs in, without verifying the email, then we have a user session and isEmailVerified is false.
I only need to check the isEmailVerified in a certain point in the app.
Also I think signing the user in, checking the field and signing the user out would be bad practise.
I'd need to reauthenticate the user, what is the best way of doing this? How can I, after the user has logged in, switch the status of isEmailVerified?
Thanks
First, you need to have the email and password to create a credential. Your user already provided this on the login page... So the email and password to persistent storage on iOS. In Android, the equivalent would be SharedPreferences.
I do not code in iOS, but this will give you the idea for the logic.
Then, when you get to that point in your app where email verified is called:
if (user.isEmailVerified) == true {
// you do not need to hold the email and password in persistent storage anymore.
// go into your persistent storage and delete the data.
} else {
// get the email and password the user saved in persistent storage.
String email = persistentStorage.getEmail();
String password = persistentStorage.getPassword();
var user = firebase.auth().currentUser;
var credentials = firebase.auth.EmailAuthProvider.credential(email, password);
user.reauthenticate(credentials);
// then, when finished reauthenticating, check whether isEmailVerified() == true;
}

Can you only allow users with a specific email address to sign up and use your app

I currently have user authentication in my app using firebase and swift 3. Is there a way to only let users with a certain email address to sign up to use my app?
Essentially what you want to do is include a boolean test to determine whether the email text contains the domain you want.
Here is a function that determines whether or not the input text contains a set domain.
func isValidEmail(testEmail:String, domain:String) -> Bool {
let emailRegEx = "[A-Z0-9a-z._%+-]+#[\(domain)]+\\.[com]{3,\(domain.characters.count)}"
let emailTest = NSPredicate(format:"SELF MATCHES %#", emailRegEx)
let result = emailTest.evaluate(with: testEmail)
return result
}
Here's an example of me using it
let customDomain = "mycompanyname"
let test = "frank#mycompanyname.com"
if isValidEmail(testEmail: test, domain: customDomain) == true {
//Test succeedes... Here you would register the users as normal
print("register \(test)")
}else{
//Test fails... Here you might tell the user that their email doesn't check out
print("register failed")
}
Additionally, I would take a look at Apples App Distribution Guide for if you want to distribute your app locally to say an employee base.
Hope this helps.
You can do the following client and backend checks to enforce this:
On the client side, you can block sign-in when an invalid email domain is provided. If you are using some federated sign in with Google or Facebook, etc, you can on return check the currentUser.email and currentUser.delete the user if the email doesn't match your domain. Google also provides an 'hd' parameter to specify the user domain if you are using GSuite.
You can use Firebase Functions onCreate event to delete a user quickly every time one is created with an invalid email domain.
If you are using database rules, you can block access if the email doesn't match:
".read": "auth != null && auth.uid == $uid" && auth.token.email.matches(/.*#mydomain.com$/)
If you are using your own backend, when getting the ID token of a user, validate it, then get the email and make sure it matches your domain, if not, you can delete the user. The Firebase Admin SDKs provide the ability to verify an ID token and delete a user by UID.

Firebase Auth (with Custom Token, for Linkedin) returns a user with no email and no data (only uid)

I'm trying to login with Linkedin and Firebase. I generate on my server the custom token, I have my private key, I use RS256 and this is my payload:
"iss" : service_account_email
"sub" : service_account_email
"aud", "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit"
"iat", Date().timeIntervalSince1970
"exp", Date().timeIntervalSince1970.advanced(by: 3600)
"uid", String.randomString(length:28)
I create the token, send it back to the app and from this I do:
Auth.auth().signIn(withCustomToken: token!, completion: { (user, error) in
I receive no error and a user back, so the token is valid. The problem is that the user has no values (no email, no displayName etc). the only thing is the uid which is the one that I set with: String.randomString(length:28)
How can I retrieve the user email and other info? In my linkedin account I have a displayname, email, picture etc. But here nothing.
Thanks
You have to set that manually. Firebase Auth has APIs to update profile (photo URL and display name) as well as email. You can send this LinkedIn data along with the custom token to your app, sign in with custom token and then update profile and email on that signed in custom token user.
By the way, set the LinkedIn ID as the UID for that user. Do not use a random string. Otherwise the next time you sign in with LinkedIn, the same user will map to another one.

Create Firebase User on ios without auto-signin [duplicate]

This question already has answers here:
Firebase kicks out current user
(19 answers)
Closed 6 years ago.
i'm writing an ios-app with firebase as backend.
In my app, there are some admins, who should be able to create new users. A new user should not be able to create an account on his own.
On web, i'm using the function
ref.createUser({
email: ctrl.user.email,
password: ctrl.user.password
}, function(error, userData) { // }
with a random password and reset the password afterwards. So the user will receive an email with a password reset link and can set a new password and log in after that. After creating the user, i'm storing all relevant userdata to the database.
On ios i'm trying to create a new user with:
FIRAuth.auth()?.createUser(withEmail: email, password: password) { (user, error) in }
But if I do it this way, I'm signed out with my admin-account and logged in with my fresh created account. Due to this, I'm not able, to store the userdata to the database, because this is restricted to admins....
Is there a way on ios to only create an user, without to auto-signin with this user?
Best wishes
Tobi
EDIT
I've written an AWS lambda function with the firebase admin sdk for node.js and create the user inside the function and trigger the function via a webservice-call from my ios-app.
Not perfect, but working....
Yes, calling createUser(withEmail:, password:) will log in a new user. To achieve what you are trying to do, I recommend a workaround by doing something like this (assume that currently an Admin is logged in):
// Create the values
var email = alreadySelectedUserEmail
var password = arc4random_uniform(1000000) // or another random number
// Send the information to the database
FIRDatabase.database().reference().child("user_data").child(email) .
setValue("lorem ipsum") // or another value
// THEN create the user, AFTER sending the data
// This will automatically log you in to the new account
FIRAuth.auth()?.createUser(withEmail: email,
password: password) { (user, error) in
// Check for any errors
if let error = error {
print error
} else {
// If there are none, LOG OUT…
try! FIRAuth.auth()!.signOut()
// …and log back into Admin (with whatever login info they have)
FIRAuth.auth()?.signIn(withEmail: adminEmail,
password: adminPassword) { (user, error) in
// Check for any errors
if let error = error {
print error
} else {
// All done, new account created!
}
}
}

Firebase/Swift 2 - How to get an authenticated users password and email

I'm trying to setup a password reset within an app using swift 2 and Firebase.
Following Firebases example:
let ref = Firebase(url: "https://<YOUR-FIREBASE-APP>.firebaseio.com")
ref.changePasswordForUser("bobtony#example.com", fromOld: "correcthorsebatterystaple",
toNew: "batteryhorsestaplecorrect", withCompletionBlock: { error in
if error != nil {
// There was an error processing the request
} else {
// Password changed successfully
}
})
How can I access an authenticated users email & password in order to pass those values to this function instead of the current mock data?
I'm not interested in sending a temporary password in a pass reset email.
I was thinking that I'd be able to access these values by something like:
let ref = Firebase(url: firebaseURL)
ref.authData.providerData.someValueHere
But I haven't been able to figure it out.
How can I access these values from the currently authenticated user?
How can I access an authenticated users email & password
Firebase does not store the user's password. Instead it stores a hash of the user's password. That means that there is no API from Firebase that returns a user's password.

Resources