How to auto signOut a firebase user in flutter? - firebase

I'm working on a flutter app with firebase as a backend and an authentication, now I want the app to have a trial version where the user can signInWithGoogle and use the app with full features ( for like one hour ), and then signs out automatically after that one hour ends.
SO FAR, I accomplished the following:1- signIn with google account.
2- add signed in user to _trial collection with timeStamp.
Future enterTrial() async {
final UserCredential user = await Auth.instance.googleSignInMethod();
final User actualUser = user.user;
try {
//_trial is a collection for users in Trial Period
await _trial.doc(actualUser.email).set({.
"name": actualUser.displayName,
"email": actualUser.email,
"creationDate": FieldValue.serverTimestamp(),
});
} catch (e) {
print(e);
}
}
WHAT's LEFT:
after one hour from signIn, signOut and move user from _trial collection to _expired collection.
so that I could check if the user is expired or not.
is there a way to automatically signOut after sometime? or to - periodically - compare creationTime with currentTime and accordingly signOut?
Thanks In Advance.

Yes You can achive this by using background_fetch package this provide you a callback function in that function you can call your logout method.

Related

FIrebase Authentication | Any triggers for when a user Signs in? [duplicate]

I see how execute a Cloud Function on user account creation:
exports.myFunction = functions.auth.user().onCreate(event => {
But I need my function to execute when the user logs in. Is there a onLogin trigger?
And can someone with 1500 points create a tag for firebase-cloud-functions?
There's no event for login, because only the client side can define exactly when a login happens. Different clients may define this in different ways. If you need to trigger something on login, figure out when that point is in your app, then trigger it from the client via a database or HTTP function.
This worked in the controller:
firebase.auth().onAuthStateChanged(function(user) { // this runs on login
if (user) { // user is signed in
console.log("User signed in!");
$scope.authData = user;
firebase.database().ref('userLoginEvent').update({'user': user.uid}); // update Firebase database to trigger Cloud Function
} // end if user is signed in
else { // User is signed out
console.log("User signed out.");
}
}); // end onAuthStateChanged
And this is the trigger in the Cloud Function:
exports.getWatsonToken = functions.database.ref('userLoginEvent').onUpdate(event => { // authentication trigger when user logs in
I made a location in Firebase Database called userLoginEvent.
One confusing bit is that in the functions console it's /userLoginEvent but in your code you must leave out the slash.
You can create your own analytics event, like login and used it as the trigger for your cloud function.
Then in your app, when the user successfully authenticate you use firebase analytics to send an event with the name you defined, like login
exports.sendCouponOnPurchase = functions.analytics.event('login').onLog((event) => {
const user = event.user;
const uid = user.userId; // The user ID set via the setUserId API.
});
You can trigger an https onCall firebase cloud function on login
ex: This is your login button trigger function which calls an https onCall function after authenticating the user.
_login() {
firebase
.auth()
.signInWithEmailAndPassword(this.state.email, this.state.password)
.then(function (user) {
var addMessage = firebase.functions().httpsCallable('myCloudFunctionName');
addMessage("whatever variable I want to pass")
.catch(error => {
console.log("I triggered because of an error in addMessage firebase function " + error)
)}
}).catch(error => {
console.log(error);
});
}
There is also another way you can do this inside Google Cloud if you enable Identity Platform for a project. Then you can follow this guide:
https://cloud.google.com/functions/docs/calling/logging
And trigger cloud functions for any of these Firebase Authentication events:
https://cloud.google.com/identity-platform/docs/activity-logging?authuser=1&_ga=2.226566175.-360767162.1535709791#logged_operations
The only problem I've just noticed is that the logs generated for Sign In event do not include the firebase app id or anything to determine which client the user logged in on which is really annoying as this was the main reason we needed to do this!

How can I create user profile and authenticate using phone and user password on flutter firebase?

There isn'y enough documentation on this subject. so I'm looking for some experiences from amazing people out here.
We need the main sign in method in the app to be using phone number as user name and user chosen password, Phone will be verified with OTP upon registration and when resetting password.
Flutter offers sign in using phone verification, as far as I know each time user has to go through OTP. I need the user to set a password and only verify phone once at signup or when resetting password.
also we wanna link the credentials to a firestore user profile (name, job, email, etc). How would we do that?
Code for sign in using email:
CustomMaterialButton(
onPressed: () async {
try {
final UserCredential _userCredential =
await _firebaseAuth.signInWithEmailAndPassword(email: _user.email, password: _user); //_user is a custom made class that has user profile data
if (_userCredential != null) Navigator.pushNamed(context, HomeScreen.screenId);
} catch (e) {
showCustomSnackBar(context, e.message);
}
},
text: "Log in"),
code for sign up:
CustomMaterialButton(
onPressed: () async {
try {
final UserCredential _newUserCredential =
await _firebaseAuth.createUserWithEmailAndPassword(email: _user.email, password: _user.password);
if (_newUserCredential != null) {
Navigator.pushNamed(context, VerifyPhoneScreen.screenId);
}
} catch (e) {
showCustomSnackBar(context, e.message);
}
},
text: "New user signup"),
Screen 1
Screen 2
Screen 3
Once a user is signed in to Firebase Authentication (whether with phone number or another method of signing in) they stay signed in, unless you either explicitly sign them out, or a compelling event (such as changing their password, disabling their account) happens.
As long as you listen to auth state changes, the app should reflect the user's sign-in state. If you're having trouble making this work in your app, edit your question to show that you tried.

Firebase Auth authStateChanges trigger

I'm using firebase to authenticate a user and create a user in firestore database :
final auth.FirebaseAuth _firebaseAuth;
Future<void> signUp(
{#required String email, #required String password}) async {
assert(email != null && password != null);
try {
await _firebaseAuth.createUserWithEmailAndPassword(
email: email, password: password);
await createUserInDatabaseIfNew();
} on Exception {
throw SignUpFailure();
}
}
With firebase, once the method .createUserWithEmailAndPassword() is executed, it triggers right after the authStateChanges which I am using in my code to send the new user in the user stream, and eventually retrieve its data from the database
Stream<User> get user {
return _firebaseAuth.authStateChanges().map((firebaseUser) {
return firebaseUser == null ? User.empty : firebaseUser.toUser;
});
}
StreamSubscription<User> _userSubscription = _authenticationRepository.user.listen((user) {
return add(AuthenticationUserChanged(user));}
if(event is AuthenticationUserChanged){
if(event.user != User.empty){
yield AuthenticationState.fetchingUser();
User userFromDatabase;
try{
var documentSnapshot = await _firebaseUserRepository.getUser(event.user.id);
userFromDatabase = User.fromEntity(UserEntity.fromSnapshot(documentSnapshot));
yield AuthenticationState.authenticated(userFromDatabase);
}
The problem that I am facing, is that because of _firebaseAuth.createUserWithEmailAndPassword, _firebaseAuth.authStateChanges is triggerd before the user is created in the database, and eventually when I try to retrieve that user, it still does not exist in the database.
I would like _firebaseAuth.authStateChanges() to be triggered after my method createUserInDatabaseIfNew runs.
How could I achieve that ?
I would like _firebaseAuth.authStateChanges() to be triggered after my method createUserInDatabaseIfNew runs.
The auth state change listener fires when the user's authentication state change, which is when their sign in completes. There's no way to change this behavior, nor should there be.
If you want to trigger when the user's registration in your app has completed, you should respond to events that signal that. So if registration means that the user is written to the database, you can use a onSnapshot listener on the database to detect user registration.
You could even combine the two:
Use an auth state change listener to detect when the sign in completes.
Inside that auth state listener, then attach a snapshot listener for the user's registration document.

Firebase and VueJS: How to handle users that login with Google and don't register in my app? User profile management

I have an app with a LOGIN page and a REGISTER page. Both pages have a "Sign in with Google" button, as well as a regular login and password input form for those that don't want to sign in with Google. I am also using FireStore to create user profile documents for registered users. When the user also logs in, the app will query the user's profile for use throughout the app. This all works fine.
I noticed that a google user does not need to "register"...he can still click the login button and it will "sign him up" automatically because that's how Google Auth Provider works. However, since he did not "register", he does not yet have a profile. In this case, I had to write some logic so a profile would be created for a Google user. Although this logic works, I just wonder if this is the best way to do this. Are there best practices for handling Google/Social logins for people skipping the traditional "registering" pages? I know most people would probably head to the register page and register, but there will undoubtedly be some people that will skip that and go start to the LOGIN page and sign in via Google that way.
Here's how I'm handling the login page with Google login button:
login.vue
async logInWithGoogle() {
try {
const provider = new this.$fireAuthObj.GoogleAuthProvider()
const userCredentials = await this.$fireAuth.signInWithRedirect(
provider
) ....
Then in my Store (in my case, Vuex state management pattern), I have the following actions:
store.js
First, this onAuthStateChanged observer will notice the new user state and do the following code:
async onAuthStateChangedAction({ commit, dispatch }, { authUser }) {
if (authUser) {
console.log('user committing from onAuthStateChangedAction...')
commit('SET_CURRENT_USER', authUser)
console.log(
'fetchUserProfile action dispatching from onAuthStateChangedAction...'
)
await dispatch('fetchUserProfile', authUser)
} else {
dispatch('logOutUser')
}
}
That onAuthStateChanged observer will fetch the user's profile (and this is the logic I am concerned with...not sure if this is an ideal way to handle user's logging in via Google for first time and bypassing registration:
async fetchUserProfile({ commit }, user) {
try {
const docRef = this.$fireStore.collection('users').doc(user.uid)
const profile = await docRef.get()
if (profile.exists) {
commit('SET_USER_PROFILE', await profile.data())
console.log(
'user profile EXISTS and set from fetchUserProfile action'
)
} else {
console.log('profile does not exist! Creating...')
await docRef.set({
displayName: user.displayName,
email: user.email,
uid: user.uid,
photoUrl: user.photoURL,
providerId: user.providerData[0].providerId,
createdAt: this.$fireStoreObj.FieldValue.serverTimestamp()
})
const p = await docRef.get()
commit('SET_USER_PROFILE', await p.data())
console.log('user profile set')
}
} catch (error) {
console.log('can not fetch profile', error)
}
},
Thanks for any tips or assurances that I am on the right (or wrong) path on handling this. Thank you!
Why not create an empty document with the user's uid and prompt them to "complete their profile"? Until they do so, force redirect them back to the profile page indefinitely.

onAuthStateChanged doesn't get called when email is verified in flutter

When a user signs up in my app he gets a verification e-mail. The onAuthStateChanged-listener gets called when a user gets created using createUserWithEmailAndPassword but not after the email got verified.
I have a separate class which handles all authentications. The following method is to sign up user
Future<FirebaseUser> signUpUser(email, password) async {
final FirebaseUser user = await _auth.createUserWithEmailAndPassword(email: email, password: password);
assert (user != null);
assert (await user.getIdToken() != null);
return user;
}
This method is called in my StatefulWidget using this method
void _signUpUser() async {
try {
await Auth().signUpUser(_email, _password)
..sendEmailVerification();
} catch (e) {
print(e.toString());
}
}
And onAuthStateChanged is set up in the initState method of my StatefulWidget
FirebaseAuth.instance.onAuthStateChanged.listen((user) {
print("Auth State Changed!");
if (user.isEmailVerified) {
print("EMail verified!");
}
}
onAuthStatechanged is triggered only in case of user Login or Logout & not on Email verification.
As Per Doc -
onAuthStatechanged Adds an observer for changes to the user's sign-in state.
The observer will be triggered in the following scenarios:
When auth().onAuthStateChanged() is first called. It will trigger with
the initial Auth state. If the user is returning from an
auth().signInWithRedirect() operation, the observer will wait for that
operation to resolve before initially triggering.
When a new user signs.
When an already signed in user signs out.
At the moment I'm providing a button to 'complete email validation'. This calls User.reload - so this appears to be enough per #Frank van Puffelen's comment above. It's much less satisfactory than getting a status update event; I may implement a loop to check the status for a period after sending an email so that the app passes through automatically.
You can simply do a firebase.auth().signOut after sending the email verification link. And when the user clicks on sign in again, it'll automatically fire onAuthStateChanged.
Use the where Function:
final FirebaseAuth _firebaseAuth = FirebaseAuth.instance;
Stream<FirebaseUser> get onAuthStateChanged {
return _firebaseAuth.onAuthStateChanged.where((user)=> user.isEmailVerified);
}

Resources