I am currently trying to convert an anonymous account into a permanent one using Android Firebase. I am using the email-password provider as a method to create an account. The docs state that you must pass a password parameter into the following code :
val credential = EmailAuthProvider.getCredential(email, password)
My code is the following, I use the FirebaseAuth instance to access the current user which then allows me to access their email however I cannot find a way to access the password:
val credential = EmailAuthProvider.getCredential(mAuth.currentUser.email, password)
Other links I have taken a look at do not improve clarity and cause further confusion.
Firebase Authentication : how to get current user's Password?
How to create "credential" object needed by Firebase web user.reauthenticateWithCredential() method?
Firebase get current user password
Additionally, the last link states that for security reasons we cannot get the password.
I am currently trying to convert an anonymous account into a permanent one using Android Firebase. I am using the email-password provider as a method to create an account.
From this sentence, I understand that you already have anonymous accounts in your project and you try to convert them into permanent users using user and password.
The docs state that you must pass a password parameter into the following code:
val credential = EmailAuthProvider.getCredential(email, password)
That is a normal requirement. Since your anonymous users can join your app without any credentials, in order to be able to convert them, you need to ask each user for an email and a password. That can be simply done in Android, using two EditText objects.
Once you got the user input, you can call getCredential() and pass those values as arguments. Once did that, you can call:
auth.currentUser!!.linkWithCredential(credential)
.addOnCompleteListener(this) { /* ... */ }
Please note that auth.currentUser represents the anonymous users. When you call linkWithCredential() and you pass the credential object as an argument, you're actually converting the anonymous user into a permanent user.
Since the current account is anonymous, it doesn't have an email and password yet.
The common flow is that you first sign in the user anonymously, without asking them for any information. Then later (when the user is ready to sign in explicitly) you ask them for their email and password, use those to create email credentials, and then link them to the anonymous account.
Related
I'm using Firebase Auth in my app. I wrote code in onStart().
private fun checkLogged() {
if (Firebase.auth.currentUser != null) {
startActivity(Intent(this#LoginActivity, MainActivity::class.java))
finish()
} else {
auth.signOut()
}
}
But when I disable or delete this user in the console, It's still logged in. How can I edit code correctly?
When a user is successfully signed in with Firebase, then it receives a token that is valid for about an hour. If you disable a user in the Firebase console, it doesn't mean that the access is restricted too. No, the user can still have access for about an hour. After that period of time, the token that was previously generated needs to be refreshed, but the operation will fail since the user account is disabled. A disabled account cannot get a new token. So the user can still have access until the access will be automatically revoked.
If you want to remove that access before the token expires, then you should consider keeping an additional list of "banned" UIDs and maintaining it over time. For example, you can keep a global array of bannedUIDs in a Firestore document, and add the UID to that array. Then, in your security rules, you can check if that particular UID is banned or not. If that UID exists inside that array, then Firebase servers will reject the operation, otherwise, it can continue to use your app.
I have the possibility that the user can choose if they want to log in with Google, Facebook, email/password, etc.
After testing my app, the following happened:
I sign up with my name, email, and password
Handle the get started logic
Verify my auth users on Firebase (grey email icon)
Sign out of the account
Now, I want to log in with Google (same email used on the sign-up with email and password)
The Google sign-in worked
Verify my auth users on Firebase (the grey email icon changed into the Google one)
Sign out of the account
Can't log in with email and password anymore but the google sign in worked
After some research, I end up with the Link Multiple Auth Providers to an Account on Android documentation
I realized I have to refactor my code to not use the FirebaseAuth.signInWith methods
This is a little except of my loginEmailAndPassword:
val credential = EmailAuthProvider.getCredential(email, password)
firebaseAuth.currentUser!!.linkWithCredential(credential).addOnCompleteListener{ authTask: Task<AuthResult> ->
if (authTask.isSuccessful) {
I have an 'else' meaning the (authTask.isSuccessful) did not happened and another 'if' with the FirebaseAuthUserCollisionException
val exception: java.lang.Exception? = authTask.exception
if (exception is FirebaseAuthUserCollisionException) {
linkAndMerge(credential)
My goal is to link and merge, and I do not know how to link the accounts (both email grey and Google on Firebase)
private fun linkAndMerge(credential: AuthCredential) {
val authenticatedUserMutableLiveData: MutableLiveData<ResponseState<UserModel>> =
MutableLiveData()
val prevUser = firebaseAuth.currentUser
firebaseAuth.signInWithCredential(credential)
.addOnSuccessListener { result ->
val currentUser = result.user
// Merge prevUser and currentUser accounts and data
// ...
}
.addOnFailureListener {
authenticatedUserMutableLiveData.value = ResponseState.Error("Error")
}
}
My questions:
Can I call something to merge prevUser and currentUser accounts. I just want to the user have the possibility of using different authentications.
I am not worried about the data because if it's the same User UID does not matter if the authentication provider
Can I still use 'createUserWithEmailAndPassword'?
Steps 1 to 9 provide the expected behavior. If you create a user with email and password and right after that you sign in with Google, the account will only be accessible with Google. Why? Because behind the scenes Firebase converts the account that was created with email and password into an account with the Google provider. Unfortunately, you cannot reverse that change.
The link in your question, is referring to the possibility to link an existing account to a specific provider. For example, if you implement anonymous authentication, then you can link that account with Google, for example. This means that the UID remains the same.
If you want to stop that mechanism from happening, then you should consider allowing the creation of different accounts for different providers. You can find this option which is called "Create multiple accounts for each identity provider" right inside the Firebase Console, in the Settings tab inside the Authentication.
I am developing Android app using Firebase. Because of that, I want to use Firebase Auth. I have following requirements:
Register/Log in using Facebook
Register/Log in using Email/Password
Register/Log in using Phone Number/Password
The first two are OK, I followed basic tutorials. However, Phone Number / Password is the problem here. Firebase supports only Phone Number/SMS Token for this (its called Phone Auth), but there is no mention about my case. I do not want to hack Firebase and use its realtime database instead of Auth 'database'. Is there any better way to achieve this?
Thank you.
If you have both email and phone of your user and you can use Admin SDK, then perhaps you could exchange users phone number to his email and login with email and password in the background.
Something like this (node.js)
admin.auth().getUserByPhoneNumber(phoneNumber)
.then(user => {
firebase.auth().signInWithEmailAndPassword(user.email, password);
});
Firebase phone authentication is using OTP(one time password). This way there is no hassle for the user to remember the password. Once authenticated, you will be registered. The sms code acts as a password. But that is for one time. Usually , users prefer such behaviour in which you dont have to remember the passwords. If you are still looking for the way you want, see this link and create a custom authentication method.
https://firebase.google.com/docs/auth/android/custom-auth
I had a similar problem -
I combined firebase auth(email + password) with (phone+otp) to get phone+password auth -
https://medium.com/#shivampesitbng/firebase-phone-password-auth-in-vue-b94f15b8fb3d
Use Fake Email:
Well, Firebase doesn't support sign in with mobile number and password but it supports email and password. So you can create a fake email with your mobile number.
Ie: 78******69#yourdomain.com
Also, you can create a complete Authentication system using it.
Registration:
Input user mobile and password and proceed to the next page.
Now use Firebase Phone Auth (OTP) to createUser. If process success, link fake email, password credentials in background.
AuthCredential credential = EmailAuthProvider.getCredential(email, password);
auth.getCurrentUser().linkWithCredential(credential);
Login:
Input mobile and password to login. Convert the mobile in fake email and then signInWithEmailAndPassword().
Forget Password:
Redirect the user to a new Page and user Phone Auth to verify the user. If successful, input a new password and change the password of the Email Auth.
My question is about the Android Account Manager. I'm not sure I understand the documentation below:
http://developer.android.com/reference/android/accounts/AccountManager.html
For the method:
public AccountManagerFuture getAuthToken (Account account, String authTokenType, Bundle options, Activity activity, AccountManagerCallback callback, Handler handler)
It says this:
If a previously generated auth token is cached for this account and type, then it is returned. Otherwise, if a saved password is available, it is sent to the server to generate a new auth token. Otherwise, the user is prompted to enter a password.
I don't understand how the Account Manager would do this for my account type. My assumption was that it would call a method defined in the AbstractAccountAuthenticator to do this, but I don't see any method that seems like it would re-submit a saved password.
To clarify, I was planning to save a refresh token as the 'password' for my account. I was then planning to submit the refresh token in place of a stored password in order to get a new access token.
I tried searching in GrepCode but I'm not used to the way code is presented there, or the code isn't so clear, because I'm still not sure how the Account Manager plans to 'resubmit' the stored password and if I can override that behavior so that it instead just refreshes the access token.
Any help is appreciated. I feel like I'm missing something really obvious here.
Override getAuthToken. In that override you will perform the above workflow. Saving the password is optional. If you don't want to save the password then in getAuthToken you just validate the token that is saved already. If the token is not valid you will prompt for the login or just refresh the token with some other mechanism as defined by your requirements.
I'm starting to write an app whereby a mobile app (Android/IPhone) will communicate with the GAE backend (Python) through a series of Web API calls using JSON.
I can't use Google Accounts for authentication so I need to implement my own auth. I have an idea of how to do this, but I'm not sure if there is a better way.
Can anyone help with some code examples/suggestions of how to achieve the below please?
Method
Mobile app calls a Login method on the server which authenticates and creates a session key in the store and returns this to the app - not sure how to generate the key/session or where on the request/response it should be.
On every call, the app passes this key for the server to authenticate and allows the action if it passes.
User should not have to login on mobile again unless they explicitly logout or lose the key.
Login Method - without key generation
class Login(webapp.RequestHandler):
def post(self):
args = json.loads(self.request.body)
email = args['e']
pwd = args['p']
ret = {}
user = User.gql('WHERE email = :1', email).get()
if user and helpers.check_password(pwd, user.password):
ret['ret_code'] = 0
ret['dn'] = user.display_name
else:
ret['ret_code'] = 1
self.response.headers['Content-Type'] = 'application/json'
self.response.out.write(json.dumps(ret))
I think you should use features webapp2 providing to implement your custom registration.
from webapp2_extras import auth
from google.appengine.api import users
class RegisterHandler(webapp2.RequestHandler):
def post(self):
email=self.request.POST['email']
password=self.request.POST['password']
#Let webapp2 handle register and manage session
user = auth.get_auth().store.user_model.create_user('own:'+str(email), password_raw=password,email=email)
#user (True, User(key=Key('User', 80001), auth_ids=[u'own:useremail#mail.com'],email='useremail#mail.com',password=u'hashed_password',...))
if not user[0]: #user is a tuple
self.response.write(user[1]) # Error message
else:
#You can extend your User Model e.g UserProfile(User): or have a UserProperty in your profile model as the example.
profile=UserProfile(user=users.User(user[1].email)).put()
self.response.write(str(profile.key()))
class LoginHandler(webapp2.RequestHandler):
def post(self):
email = self.request.POST.get('email')
email = self.request.POST.get('password')
# Try to login user with password
# Raises InvalidAuthIdError if user is not found
# Raises InvalidPasswordError if provided password doesn't match with specified user
try:
auth.get_auth().get_user_by_password('own:'+email, password)
#Return user_session with User id,
except InvalidPasswordError, InvalidAuthIdError:
#Error
You can check user logged in by:
if auth.get_user_by_session():
#Logged in
else:
#Not logged in
On your client application(Android, IOS). You only have to store the response cookie and send it for every sub sequence requests.
Good luck :)
Have a look at webapp2 and webapp2 extras with sessions, auth and JSON
I cannot see why you would need a session?
Sessions on App Engine are persisted in the data store, so if you can keep your requests stateless, I encourage you to do so.
As you will have your own user service which will authenticate the users, I suggest you use Digest authentication, as the secret is never included in the request.
There are libraries implementing Digest for most client and server platforms.
If you dont explicitly want to use Sessions etc. you can simply use the Datastore. Try following this:
Get a unique deviceID/email to identify each unique user.
On request from a specific user, generate a random authentication key, and store it attached to the user's email/deviceID and probably the current timestamp and a loggedIn flag.
SO you have:
User email/id: someone#example.com
password: xxxxxxxxxx
Key : 2131231312313123123213
Timestamp: 20:00 12-02-2013
loggedIn : boolean value
This can be database model. Now whenever the user logs in:
Check email, password combination.
If valid, generate random key, and update the datastore with the new key
update timestamp with current time, and set loggedIn to True
Now return the key back to the client (Android/iPhone) in a JSON object.
Now on every request, Check the received key against the one in your datastore, and if loggedIn flag is set to true. If both OK, process the request.
Also, on Logout:
Just set the loggedIn flag in the datastore to False.
Hope this helps :)
Try gae-sessions for session management. It creates secure cookies for you and allows you to easily associate data with each user. Just provide your own logic for the initial authentication.
It was built specifically for App Engine and is pretty popular and super fast/scalable.
https://github.com/dound/gae-sessions
There are many ways to do this.
1) When you check the users login details if it checks out you can then create a random UUID or string and store the User object in memcache with the random string as the Key and the User Object as the value. Then return the random string along with your response headers. On the mobile when you are parsing the response, get this header and store it in the local cache. On all further requests keep sending this key back in the request header and in your controller get the User object from memcache using this key and proceed. If the object is not in memcache you can send back a response which prompts the user to log in.
2) If you dont want to use memcache you can store the User object in the session and on the client side while parsing the response get the session id from the response. Its usually JSESSIONID. Then store that and resend it with further requests. In the controller you can check if the current session has the user object else force login.
1) Another way to go would be to return the appengine key for the user along with the response and resend it.
Just google get response header from response. Then get the SESSIONID/JSESSIONID header, store and add the field with the same name and value to all further request headers. Thats the easiest way.
My first answer on stackoverflow and no code exapmles, dangit if only i knew python.