Firebase Authentication ( Email & Password ) how to check existing user - android

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.

Related

AWS Cognito: how to delete an identity programmatically?

In my Android app, I use AWS Cognito to allow my users to sign up and login. I configured my identity pool so it allows guest users (unauthenticated users) in my app.
So everytime my user logs in or logs out, I call the following code to get an identity ID:
CognitoCachingCredentialsProvider credentialsProvider = new CognitoCachingCredentialsProvider(
this,
"eu-central-1:12345678-1234-5678-9012-1234567890ab",
"eu-central-1");
credentialsProvider.clearCredentials();
credentialsProvider.getIdentityId();
When my user logs in, it creates a new identity the first time, then the user gets the same identity everytime he logs in. But everytime he logs out, a new identity is created, since he's now a "guest" user.
Is that the expected behavior? And if yes, how can I remove an unused identity programmatically (for example when the user logs in, so the "guest" identity is now useless, since a new one will be created when he logs out)?
Thanks for your help.
From the docs, we have:
getIdentityId() Gets the Cognito identity id of the user. The first time when this method is called, a network request will be made to retrieve a new identity id. After that it's saved in SharedPreferences.
clearCredentials() Destroy all the saved AWS credentials but not the identity Id.
so, the behavior you described is totally normal according to the docs.
Now, let's find an approach to deal with the problem.
if you want to continue with your proposition, and delete the identity programmatically after the logout, you can use deleteUser() method from AWSJavaSDK.
However, if you want to keep the same identity for the same user after the logout, you shouldn't clear the cache, cause the won't keep the user any trace of its identity.
I hope this will help.

What to do if token expired

I have communicate with API using retrofit. When the user is log in, I save account to database and when the user go to app next time, I get data from database (so I skipped login screen). Problem is when user's token expires.
How to handle the situation?
in login fragment
PSEUDOCODE
user = ... //get user from database
if(user != null) {
startActivityAccountActivity();
}
//onButtonClick
emailLogin();
Don't go to your "logged in" activity just because you have a token saved, because as you have correctly noticed, it may be invalid. Try authenticating with the API when you get the token, and only go to the "logged in" activity if it indeed worked. Otherwise proceed as if there was no token saved (and remove the expired one from the database).
You should also note that the token may expire when the user is in the "logged in" activity. For example, the user logged in, used the app and then went to another app from the recents screen. A week later he/she returns to your app with the "logged in" activity open, but in the mean time the token has expired and nothing will work. So you should also check if the token still works there, maybe in the onStart() of the activity.
As indramurari said, you can also handle it on the backend if you control it. But keep in mind that it doesn't solve your inherent problem of handling expired tokens, a refresh token may also expire and you are back to square one. If you make refresh tokens not expire you can just make the login tokens not expire. (This paragraph would be a comment on his answer, but I don't have enough reputation.)
It depends on your back end security level. You have two options to handle this situation.
Build some mechanism on back end side so that your server will send some refresh-token along with the user's token at the time of login to Android device. Whenever user's token get expired then request from Android device to your server to obtain new user's token by sending old user's token along with refresh-token. And you can use that new user's token for future. Repeat this whenever user's token get expired.
Note - refresh-token is for validating if it is valid resource who is requesting for a user's token.
You can delete the user account from database and tell user to Re-Login.

Firebase Authentication State Change does not fire when user is disabled or deleted

Under The Hood
I am using Firebase Authentication in my Android app to sign up/in users using Google, Facebook and Email/Password. So far, almost everything works fine except for a single scenario.
The Scenario
I need to disable or delete user accounts from the Firebase console sometimes to ban some users of my app.
In that case, when I disable or delete that particular user, the user must get logged out from the app instantly and should not be able to use it any further.
The Bug
I have used the AuthStateListener to listen for authentication state changes and log out the user automatically as soon as their account is disabled or deleted.
FirebaseAuth.getInstance().addAuthStateListener(firebaseAuth -> {
if (firebaseAuth.getCurrentUser() == null) {
Intent intent = AuthFlowActivity.getCallingIntent(AuthFlowActivity.FORCE_LOGOUT);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
activityExitAnimation(BaseAppActivity.this);
}
});
But I have never seen the AuthStateListener fire any events for these actions. So I am unable to log out the user instantly and the user can still keep on using the app.
I would appreciate if anyone can help in resolving this issue.
Disabling or deleting a user account does not fire an auth state change. Nor should it, the user is still authenticated. In at most an hour, Firebase Authentication will try to refresh the access token for the user. That refresh will fail, at which point the user will become unauthenticated and the auth state change event will fire.
If you're looking to revoke the user's authorization immediately, you will have to do so in another part of your application logic. A common way to do this is by having a blacklist in your application, e.g. in the Firebase Database:
/bannedUsers
uidOfBannedUser: true
Now when you delete/disable a user's account in the Autentication panel, you also add their uid to the list of banned users in the database.
The database can then be secured against access from unauthorized users by adding a clause to your database security rules, e.g.
{
"rules": {
"bannedUsers": {
".read": true,
".write": false // only admins can write these
},
"messages": {
".read": "auth != null && !root.child('bannedUsers').child(auth.uid).exists()"
}
}
}
If you use a different back-end, the implementation will be different. But a blacklist like this is a common approach to ban users. You'll find that you may even care little enough about their authentication that you only ban them, instead of deleting their credentials (which they could simply recreate).

How to do a email verification to firebase user for signup and email update using FirebaseAuth? [duplicate]

Question says it all. In Firebase, how do I confirm email when a user creates an account, or, for that matter, do password reset via email.
I could ask more broadly: is there any way to send emails out from Firebase? E.g. notifications, etc. This isn't the kind of thing you would usually do client-side.
Update
Note that this was never a very secure way of handling email verification, and since Firebase now supports email verification, it should probably be used instead.
Original answer
I solved the email verification using the password reset feature.
On account creation I give the user a temporary (randomly generated) password. I then trigger a password reset which will send an email to the user with a link. The link will allow the user to set a new password.
To generate a random password you can use code similar to this:
function () {
var possibleChars = ['abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!?_-'];
var password = '';
for(var i = 0; i < 16; i += 1) {
password += possibleChars[Math.floor(Math.random() * possibleChars.length)];
}
return password;
}
Note that this is happening on the client, so a malicious user could tamper with your logic.
This would need to be done outside of firebase. I store users at /users/ and keep a status on them (PENDING, ACTIVE, DELETED). I have a small service that monitors users of a PENDING status and sends out a confirmation email. Which has a link to a webservice I've created to update the user status to ACTIVE.
[Engineer at Firebase - Update 2014-01-27]
Firebase Simple Login now supports password resets for email / password authentication.
Each of the Simple Login client libraries has been given a new method for generating password reset emails for the specified email address - sendPasswordResetEmail() on the Web and Android, and sendPasswordResetForEmail() on iOS.
This e-mail will contain a temporary token that the user may use to log into their account and update their credentials. This token will expire after 24 hours or when the user changes their password, whichever occurs first.
Also note that Firebase Simple Login enables full configuration of the email template as well as the sending address (including whitelabel email from your domain for paid accounts).
To get access to this feature, you'll need to update your client library to a version of v1.2.0 or greater. To grab the latest version, check out https://www.firebase.com/docs/downloads.html.
Also, check out https://www.firebase.com/docs/security/simple-login-email-password.html for the latest Firebase Simple Login - Web Client docs.
As at 2016 July, you might not have to use the reset link etc. Just use the sendEmailVerification() and applyActionCode functions:
In short, below is basically how you'll approach this, in AngularJS:
// thecontroller.js
$scope.sendVerifyEmail = function() {
console.log('Email sent, whaaaaam!');
currentAuth.sendEmailVerification();
}
// where currentAuth came from something like this:
// routerconfig
....
templateUrl: 'bla.html',
resolve: {
currentAuth:['Auth', function(Auth) {
return Auth.$requireSignIn() // this throws an AUTH_REQUIRED broadcast
}]
}
...
// intercept the broadcast like so if you want:
....
$rootScope.$on("$stateChangeError", function(event, toState, toParams, fromState, fromParams, error) {
if (error === "AUTH_REQUIRED") {
$state.go('login', { toWhere: toState });
}
});
....
// So user receives the email. How do you process the `oobCode` that returns?
// You may do something like this:
// catch the url with its mode and oobCode
.state('emailVerify', {
url: '/verify-email?mode&oobCode',
templateUrl: 'auth/verify-email.html',
controller: 'emailVerifyController',
resolve: {
currentAuth:['Auth', function(Auth) {
return Auth.$requireSignIn()
}]
}
})
// Then digest like so where each term is what they sound like:
.controller('emailVerifyController', ['$scope', '$stateParams', 'currentAuth', 'DatabaseRef',
function($scope, $stateParams, currentAuth, DatabaseRef) {
console.log(currentAuth);
$scope.doVerify = function() {
firebase.auth()
.applyActionCode($stateParams.oobCode)
.then(function(data) {
// change emailVerified for logged in User
console.log('Verification happened');
})
.catch(function(error) {
$scope.error = error.message;
console.log(error.message, error.reason)
})
};
}
])
And ooh, with the above approach, I do not think there's any need keeping the verification of your user's email in your user data area. The applyActionCode changes the emailVerified to true from false.
Email verification is important when users sign in with the local account. However, for many social authentications, the incoming emailVerified will be true already.
Explained more in the article Email Verification with Firebase 3.0 SDK
What I did to work around this was use Zapier which has a built in API for firebase. It checks a location for added child elements. Then it takes the mail address and a verification url from the data of new nodes and sends them forwards. The url points back to my angular app, which sets the user email as verified.
As I host my app files in firebase, I don't need have to take care of any servers or processes doing polling in the background.
There is a delay, but as I don't block users before verifying mails it's ok. Zapier has a free tier and since I don't have much traffic it's a decent workaround for time being.
The new Firebase SDK v3 appears to support email address verification, see here (put your own project id in the link) but it doesn't appear to be documented yet.
I have asked the question on SO here
See #SamQuayle's answer there with this link to the official docs.
As noted by various others Firebase does now support account related emails but even better, as of 10 days ago or so it also supports sending any kind of email via Firebase Functions. Lots of details in the docs and example code here.
I used following code to check the email verification after creating new account.
let firAuth = FIRAuth.auth()
firAuth?.addAuthStateDidChangeListener { auth, user in
if let loggedUser = user {
if loggedUser.emailVerified == false {
loggedUser.sendEmailVerificationWithCompletion({ (error) in
print("error:\(error)")
})
}
else {
print(loggedUser.email)
}
} else {
// No user is signed in.
print("No user is signed in.")
}
}
I used MandrillApp. You can create an API key that only allows sending of a template. This way even thought your key is exposed it can't really be abused unless someone wants to fire off tonnes of welcome emails for you.
That was a hack to get myself off the ground. I'm now enabling CORS from a EC2 that uses the token to verify that the user exists before extending them a welcome via SES.

best way to Logout from my app with own Account type

I have my own type account in my application and I putted Log out button in my app. I would like to find out what is better way for Logging out
I wonder is it better to removeAccont like this:
mAccountManager.removeAccount(account, new AccountManagerCallback<Boolean>() {
#Override
public void run(AccountManagerFuture<Boolean> future) {
try {
if (future.getResult()) {
}
} catch (Exception e) {
e.printStackTrace();
}
}
}, null);
or change password?
or remove Auth Tokens?
This depends on many things. Primarily: What do you want to accomplish?
First of all, if you actually log the user out, the auth tokens would be invalidated and hence you can just remove them. This is basically what logging out means.
Whether you remove the password, or still keep it saved, is entirely up to you. Although, you probably should not save the password itself on an android device. You should rather save a refresh token with which you can get a new access token as the accounts password. This stored data is always a security risk, and exposing user passwords is not a good idea.
If you remove the account, the users device will be kept "clean", on the other hand: How many accounts do you suppose a normal user is going to have?
If you keep the account, but just remove the password and tokens, you can still query the account manager to support AutoCompleteTextView to facilitate the next user login.
What I do is:
Invalidate the tokens
Remove access token
setPassword(account, null) (Password is the refresh token, which got invalidated anyways)
Keep the account.
And as mentioned earlier, I use an AutoCompleteTextView to suggest the old account at the next login.

Categories

Resources