Firebase Auth Login must allow single device login - ios

I am developing app with the help of Firebase backend and I am using Firebase Auth for login into my application. I have done all integration and every thing and my app is working fine.
But I want only single session with single user as right now with single userId I am able to login through multiple devices.
So I want to restrict user that at a time user can login in in single device.
I am using Custom auth with username password login :
Auth.auth().signIn(withCustomToken: customToken ?? "") { (user, error) in
// ...
}
If user login with same id in another device I want to show alert that "You are already logged in another device".
Is there any possibility in Firebase Auth lib for single user single session?
Edit : Suggested duplicate question will not solve my query fully though it help me to understand scenireo and help to solve my problem.
Thanks #Frenk for pointing this out.

I search a lot on above issue which I was facing through firebase authentication and after lots of research I ended up with below solution which was working as per my requirements.
First of all firebase not providing this in their library so we need to apply our custom logic here to achieve this 1 session user login in our app.
Step 1: You need to add new child "SignIn" at your root of Database.
Step 2: While Auth.auth().signIn() return success in that block we need to check below Flag that is User already signIn in any other device ? for that I have create one method as mention below.
func alreadySignedIn() {
// [START single_value_read]
let userID = Auth.auth().currentUser?.uid
ref.child("SignIn").child(userID!).observeSingleEvent(of: .value, with: { (snapshot) in
// Get user value
if let dict = snapshot.value as? [String: Any] {
if let signedIn = dict["signIn"] as? Bool {
if signedIn {
self.signOut()
}
else {
// change the screen like normal
print("First Session of user")
self.writeNewUserSigin(withUserID: userID!)
}
}else{
self.writeNewUserSigin(withUserID: userID!)
}
}else{
print(snapshot)
self.writeNewUserSigin(withUserID: userID!)
}
}) { (error) in
print(error.localizedDescription)
}
// [END single_value_read]
}
By this method we are checking that current user uId have in our SignIn Child with True value if data is there in our database with Boll value True we need to handle that and show some alert and signOut from firebase.
Note : As we allowed user to sign-in and than we are checking that
user already signin in any other device so if its returning True we
need to SignOut() from firebase.
Now last step while user manually signOut from the app
Step 3: While user click on SignOut button in app we need to update our Child with False value in it so after onwards user can able to SignIn in any other device. For that we can use below method.
func updateUserSigIn(withUserID userID: String) {
//Update SignIn Child with flase value on current UID
// [START write_fan_out]
let post = ["signIn": false]
let childUpdates = ["/SignIn/\(userID)": post]
let ref = Database.database().reference()
ref.updateChildValues(childUpdates) { (error, refDatabase) in
if (error != nil) {
print("error \(String(describing: error))")
}else {
print("New user Saved successfully")
self.signOut()
}
}
// [END write_fan_out]
}
Thats it now only one app user session will allow.
Hope this will helps others.
Thanks for this thread as I got some hints from this answer.

Related

How to check Google sign-in validation in iOS after remove access from user Security account

How to validate or check the google sign in user, if the user is removed access from their account management or still valid? image shown below. i have tried out
if(GIDSignIn.sharedInstance()?.currentUser != nil)
and
guard let googleSignIn = GIDSignIn.sharedInstance() else { return } if (googleSignIn.hasPreviousSignIn()) { googleSignIn.restorePreviousSignIn() }.
but it doesn't work out. How to validate the user if removed access or not.
Can anyone help on this?
Do like this, you will get the call back in the delegate method. If it fails with an error, you have to ask the user to re-login.
guard let googleSignIn = GIDSignIn.sharedInstance() else { return }
if (googleSignIn.hasPreviousSignIn()) {
googleSignIn.restorePreviousSignIn()
}

Is it possible to ask for the user's PIN, Face ID or Touch ID before he sees a UIView?

I'd like to have the history section of an app locked for everyone besides the person who owns the phone. I don't like forcing the user to make an account or make a new PIN just for this app. Can I authorize using the PIN, Face ID or Touch ID he has already set up?
The Local Authentication framework will handle this.
Here is part of an Apple code sample:
/// Logs out or attempts to log in when the user taps the button.
#IBAction func tapButton(_ sender: UIButton) {
if state == .loggedin {
// Log out immediately.
state = .loggedout
} else {
// Get a fresh context for each login. If you use the same context on multiple attempts
// (by commenting out the next line), then a previously successful authentication
// causes the next policy evaluation to succeed without testing biometry again.
// That's usually not what you want.
context = LAContext()
context.localizedCancelTitle = "Enter Username/Password"
// First check if we have the needed hardware support.
var error: NSError?
if context.canEvaluatePolicy(.deviceOwnerAuthentication, error: &error) {
let reason = "Log in to your account"
context.evaluatePolicy(.deviceOwnerAuthentication, localizedReason: reason ) { success, error in
if success {
// Move to the main thread because a state update triggers UI changes.
DispatchQueue.main.async { [unowned self] in
self.state = .loggedin
}
} else {
print(error?.localizedDescription ?? "Failed to authenticate")
// Fall back to a asking for username and password.
// ...
}
}
} else {
print(error?.localizedDescription ?? "Can't evaluate policy")
// Fall back to a asking for username and password.
// ...
}
}
}

phone authentication using firebaseUI ios swift

i'm ios fresher. i want to retrieve phone number with country code from the default firebase phone authentication screen.
This is default screen that firebase provides. how can i retrieve country code & phone number on verify buttonClick that is enter by the user and how can i get verify buttonClick event? Is there any library provided function to get buttonClick?
i am stuck here
fileprivate func startLogin() {
self.authUI?.delegate = self
self.authStateListenerHandle = self.auth?.addStateDidChangeListener { (auth, user) in
if user != nil {
print(user)
}else {
do{
try self.auth?.signOut()
print("singning out done")
}catch{
print("Error while signing out!")
}
let phoneProvider = FUIPhoneAuth(authUI: self.authUI!)
self.authUI?.providers = [phoneProvider]
phoneProvider.signIn(withPresenting: self.rootController!, phoneNumber: nil)
}
}
}
this code open phone number login screen for me, bt after providing phone no. when i click to the verify button i have to pass user's phone no. in bellow code to send opt on users mobile, bt i don't know how can i get verify buttonClick event & how can i retrieve phone no. & country code that user input in the phone authentication screen.
PhoneAuthProvider.provider().verifyPhoneNumber(("need to pass phone number with country code here")!, uiDelegate: nil) { (verificationID, error) in
if let error = error {
// self.showMessagePrompt(error.localizedDescription)
return
}
// Sign in using the verificationID and the code sent to the user
// ...
}
Please also explain me right flow of verification.
Why dont you use the Firebase methods to access the phone number once the tocken is verified?
Access the tocken and verify the credibility and after that you can use decodedTocken.phone_number property . Use below to access the phone number
admin.auth().verifyIdToken(idToken).then(function(decodedToken) {
var uid = decodedToken.phone_number;
// ...
}).catch(function(error) {
// Handle error
});
Maybe after you access the phone number you can use the string and break down the country code, just a sugesstion, take a look at the below described answer with how to verify the phone number as well
https://stackoverflow.com/a/45227042/10021979

How to check whether the user is new user or old user

I have one login screen, which have email, password. And in register screen after user registred they will come to login screen to login.
That time I need to check , if the user is first time user or old user. If first time user means I need to redirect them to my feedback screen. Or old user means I need to redirect them to my home screen. How to do that with firebase?
Her my code for login screen :
#IBAction func loginWithUserNamePassword(){
loginWithMailAndPassword((username.text?.trimWhiteSpace)!, password: (password.text?.trimWhiteSpace)!) { (user, error) in
if error != nil{
KRProgressHUD.dismiss()
SCLAlertView().showError("Login Error", subTitle: error!.localizedDescription)
}
else {
KRProgressHUD.dismiss()
if user!.emailVerified{
currentUser = user
enableSync()
self.callHomescreen()
}
else
{
AlertView().showError("Login Error", subTitle: "This email is has not been verified yet")
}
}
}
}
Or else in my feed back screen there are some text fields. And the model class is :
var feedbackData = [files]()
class files {
// having some string variables
}
By using this, if my data is empty in my feedback screen redirect the user to feedback screen or else redirect them to home screen. Can we do that?
Updated :
if profileData.FirstName.characters.count <= 0 {
print("Home screen calling")
}
else if profileData.FirstName.characters.count > 0 {
print("feedback screen calling")
}
Thought of trying like this. But no use.
If I understand your question currectly, once user is logged in, you want to check the creation date of the use account. To do so you have two options:
The server side. If you are using Firebase database just add the date of creation. Firebase documantation does not offer a method to get the creation date on the app side.
The app side. User user defaults, when the user login in the first time set the date for that user. When you get to the login screen again, check for existance. I would reccomend using the user id as the key.
For example:
Your user just logged in, you want to check if it the first time that he did:
if let displayName = FIRAuth.auth()?.currentUser?.displayName {
//Make sure we have the user
if UserDefaults.standard.bool(forKey: displayName) {
// try to get the user default for the spacific key
let wasConnected = UserDefaults.standard.bool(forKey: displayName)
if wasConnected {
print("This user was connected")
}
} else {
// This user was never connected
// We set the default to his ID
UserDefaults.standard.set(true, forKey: displayName)
UserDefaults.standard.synchronize()
}
}
To use the date, I think the easiest way is to convert the date to string.
Fiddle with the code to do exactly what you want.

Removing Firebase authState upon viewDidDisappear

I'm using Firebase's new framework and I'm attempting to monitor the login state of the user on both the Login and Signup VC's separately. The problem is if the login state changes on the SignUp view the Auth State on the Login view gets called as well. My question is, how do I remove the auth state? I found the syntax on the Firebase website but am a little confused on what to pass in considering my code for the auth state:
FIRAuth.auth()?.addAuthStateDidChangeListener { auth, user in
if let theUser = user {
// User is signed in.
print("LOGGED IN!!!! :::: \(theUser)")
self.dismissViewControllerAnimated(true, completion: nil)
} else {
// No user is signed in.
print("Need to login first.")
}
}
Code to use to remove the auth, but unsure what to pass in.
FIRAuth.auth()?.removeAuthStateDidChangeListener(FIRAuthStateDidChangeListenerHandle)
Says I pass in a FIRAuthStateDidChangeListenerHandle, but how do I obtain this, or do I rewrite my authState code differently?
Just store the auth in a variable
self.authListener = FIRAuth.auth()?.addAuthStateDidChangeListener { auth, user in
if let theUser = user {
// User is signed in.
print("LOGGED IN!!!! :::: \(theUser)")
self.dismissViewControllerAnimated(true, completion: nil)
} else {
// No user is signed in.
print("Need to login first.")
}
}
and remove it later
FIRAuth.auth()?.removeAuthStateDidChangeListener(self.authListener)

Resources