phone authentication using firebaseUI ios swift - ios

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

Related

Get Current Active user from the Zoom iOS SDK Custom Meeting implementation

I have implemented the Zoom iOS SDK to work with a custom UI. Everything works just as its supposed to but I haven't been able to figure out how I can get the userID of the currently active user.
I have implemented the below delegate method which tells about the current active video user, but unfortunately it shows all the other participants in the meeting except me.
func onSinkMeetingActiveVideo(_ userID: UInt) {
if let service = MobileRTC.shared().getMeetingService(), let username = service.userInfo(byID: userID)?.userName {
print("\(#function) : \(userID) : \(username)")
}
}
I need to know who is the current active user even if its me who is talking.
You can retrieve this kind of information from meeting service MobileRTCMeetingService.
MobileRTCMeetingService
func getActiveUserId() -> UInt? {
if let meetingService = MobileRTC.shared().getMeetingService() {
return meetingService.activeUserID()
}
return nil
}
Extra note: in Zoom there is also the concept of Pinned User that overrides active user in active video cell.
Pinned user id can be retrieved in this way:
func getPinnedUserId() -> UInt? {
if let meetingService = MobileRTC.shared().getMeetingService(), let userList = meetingService.getInMeetingUserList(){
for userId in userList {
if let userId = userId as? UInt, meetingService.isUserPinned(userId) {
return userId
}
}
return nil
}
return nil
}
So in order to establish which is the user id of the video in active video cell you have to check both, giving priority to pinned user.
let currentVideoUserId = getPinnedUserId() ?? getActiveUserId()
During the meeting you will never been the active user in your own video cell because even if your are speaking, you will continue to see the other person in active video cell.
On the other side if you are interested to know who is talking then you have to retrieve the user list and check the audioStatus [MobileRTCAudioStatus].
MobileRTCAudioStatus
MobileRTCMeetingUserInfo
Just pay attention that you can have more than one user speaking at the same time.
There is also another callback that can be useful if you are interested in active speaker user: it is the onSinkMeetingActiveVideoForDeck in MobileRTCVideoServiceDelegate
MobileRTCVideoServiceDelegate
According to the documentation it should be fired every time that there is a new speaker. It is used by ZOOM UI for changing the yellow frame around the active speaker user.
I according to the documentation, in order to get the current active video user info you should use the following class: MobileRTCMeetingUserInfo.
Check the doc for the video status class MobileRTCVideoStatus: https://marketplacefront.zoom.us/sdk/meeting/ios/interface_mobile_r_t_c_video_status.html
and you will see that is related with the MobileRTCMeetingUserInfo:
https://marketplacefront.zoom.us/sdk/meeting/ios/interface_mobile_r_t_c_meeting_user_info.html
On that class you will find info of the current user.
Hope you can figure out your problem!
Regards!
Gastón Montes.

Firebase Auth Login must allow single device login

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.

iOS Firebase sign in. Show activity indicator after Google account choosing

I have a ViewController with a Sign in button used to sign in into Firebase with a Google Account:
GIDSignIn.sharedInstance().signIn()
When I click the button, this appears:
Google account choosing
After selecting an account and if the authentication is successful, I want to load a second ViewController. For this, I have a listener in the first ViewController that will sign in again when the authentication state changes, this time successfully, without asking the account again and sending me directly to the second ViewController:
Auth.auth().addStateDidChangeListener({ auth, user in
if let _ = user {
GIDSignIn.sharedInstance().signIn()
}
})
The problem is that I want an activity indicator to be shown when I go back to the first ViewController from the account chooser. Because the app may be there for a few seconds during the authentication process and I don't want the user to tap again the Sign In button, while the first signing in hasn't already finished.
I need a way to recognise that a signing in process is taking place, to show an activity indicator that locks the screen to prevent the user from tapping again Sign in.
WORKAROUND 1
When I click the Sign in with Google button, I set an UserDefaults integer as 1. Then, when the ViewController is reloaded after the Google account chooser, I look for this integer and if it's 1, I don't stop the activity Indicator.
Because I want the activity indicator shown since the user clicks the button until the authentication is completed.
When button is clicked I do:
GIDSignIn.sharedInstance().signIn()
UserDefaults.standard.set(1, forKey: "signingIn")
UserDefaults.standard.synchronize()
In viewWillAppear I do:
if let _ = user {
GIDSignIn.sharedInstance().signIn()
} else {
if UserDefaults.standard.integer(forKey: "signingIn") != 1 {
self.stopActivityIndicator()
} else {
UserDefaults.standard.set(0, forKey: "signingIn")
UserDefaults.standard.synchronize()
}
}
When the authentication is completed, in GIDSignInDelegate there is the function that will be called. In this function, the activity indicator must be stopped:
// The sign-in flow has finished and was successful if |error| is |nil|.
- (void)signIn:(GIDSignIn *)signIn didSignInForUser:(GIDGoogleUser *)user withError:(NSError *)error;
WORKAROUND 2
I do a put the signIn Google function into a completion handler but it doesn't work:
self.completionHandlerSigIn {
self.stopActivityIndicator()
}
And the function is this:
func completionHandlerSigIn(completion: () -> Void) {
GIDSignIn.sharedInstance().signIn()
}
The problem is that the view is reloaded during the sign in process, after the account choosing. I need a way to recognize that I come from the Google Account choosing screen.
Just show the loading indicator right when the user clicks sign in, then hide it either when the authentication process returns with error or after processing the result. I don't use google sign in, but I can give you my example with Twitter.
#IBAction func onTwitterClicked(_ sender: UIButton) {
AuthManager.shared.loginWithTwitter(self)
}
Here is the loginWithTwitter method in AuthManager:
func loginWithTwitter(_ viewController:BaseController) {
self.provider = .twitter
viewController.showLoadingPanel()
TWTRTwitter.sharedInstance().logIn(completion: {session, error in
guard (error == nil) else {
viewController.hideLoadingPanel()
viewController.showInfoAlert("Oops", error!.localizedDescription, nil)
return
}
let credential = TwitterAuthProvider.credential(withToken: session!.authToken, secret: session!.authTokenSecret)
self.auth.signIn(with: credential, completion: {user, error in
viewController.hideLoadingPanel()
guard error == nil else {
viewController.showInfoAlert("Oops", error!.localizedDescription, nil)
return
}
self.tryConfirmUserInFirestore(user, viewController)
})
})
}

What's the iOS API for AWS Cognito User Pool Custom Authentication Flow?

Amazon docs docs outlines how its custom authentication flow works. But there are only passing mentions of iOS.
I have a working authentication system using AWS User Pools and its Custom Authentication Flow using Python Triggers and an iOS Swift app.
But there's a detail still troubling me - see comment after code.
In the AWSCognitoIdentityCustomAuthentication handler I've got this:
func getCustomChallengeDetails(_ authenticationInput: AWSCognitoIdentityCustomAuthenticationInput, customAuthCompletionSource: AWSTaskCompletionSource<AWSCognitoIdentityCustomChallengeDetails>) {
self.customAuthenticationCompletion = customAuthCompletionSource
if authenticationInput.challengeParameters.count > 0 {
DispatchQueue.main.async {
if let code = self.codeTextField.text {
let details = AWSCognitoIdentityCustomChallengeDetails(
challengeResponses: ["CODE" : code])
details.initialChallengeName = "CUSTOM_CHALLENGE"
customAuthCompletionSource.set(result: details)
}
}
}
func didCompleteStepWithError(_ error: Error?) {
// handling code
}
}
The first call of getCustomChallengeDetails() has an empty list for challengeParameters. The second call has a correctly populated challengeParameters
The method didCompleteStepWithError(_ error: Error?) misled me as I thought it only called when an error occurs but is in fact also called on success with error set to nil.
I also have a UIViewController that prompts the user for a CODE which they've been emailed by my server code. When the user submits the CODE I call this:
if let code = codeTextField.text {
let details = AWSCognitoIdentityCustomChallengeDetails(
challengeResponses: ["CODE" : code])
details.initialChallengeName = "CUSTOM_CHALLENGE"
self.customAuthenticationCompletion?.set(result: details)
DispatchQueue.main.async {
self.dismiss(animated: true, completion: nil)
}
}
This works. The server code will authenticate users who enter correct CODE values but deny those who submit an incorrect value for CODE.
But why the two customAuthenticationCompletion?.set(result: details) calls?
Can anyone say where I've taken a misstep?

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.

Resources