Keeping a User Logged in with Firebase (Custom iOS Authentication) - ios

We are new programmers trying to develop a meeting app based on google maps. And we are constantly researching and trying to learn swift coding and Xcode. Now we've put together a login system using Firebase and it's Auth features and our app currently is able to create a new user and save it to Firebase database and then the user can log into their account. This is, as we see it, a very basic authenticator function.
Now we want to be able to keep the user logged in after signing up in a fashion like Instagram and some other apps have (Logging in once and then not being asked to log in again until the user signs out explicitly.)
We've done some research about these methods and learned about the existence of "sessions" and "Login Tokens" but it seems like every database/app combination requires a different kind of approach.
We want to know what kind of options do we have to keep track of a user property within the rest of the app, like a constant that applies and that can be called from all of our codes and what could we do to implement a one time login function using swift and firebase/firestore combination?
Also we are new to Stackoverflow so hello everyone and we are sorry if we asked a previously asked question.
We wish everyone easy coding!

If you are using Firebase then you could use the Auth module it comes with import FirebaseAuth.
in your override viewDidAppear() you can add the check below and provide functionality
override viewDidAppear(){
super.viewDidAppear()
if Auth.auth().currentUser != nil {
// User is signed in.
// ...
} else {
// No user is signed in.
// ...
}}
if you want to get the currentUID for the user that was set by Firebase you can also use guard let uid = Auth.auth().currentUser?.uid else{return}

Related

Users Sync between Firebase Custom Auth and existing app and users database

The company I work for has a production ROR web application that handles user authentication using devise on backend. I´ve been asked to develop a mobile app using specific IONIC 3 with firebase template, This app works along with existing ROR web app and I cannot modify backend auth, so I implemented Firebase´s Custom Token authentication and had it to work. For testing purposes I registered manually user accounts in Firebase console using existing username and uids on my baackend, but when I try to login using a user account that is not manually registered, I get the following exception "there is no user record corresponding to this identifier" I know it is because there is no user wit that uid in firebase, but reading the documentation I found here it says "...After a user signs in for the first time, a new user account is created and linked to the credentials—that is, the user name and password, phone number, or auth provider information—the user signed in with. This new account is stored as part of your Firebase project, and can be used to identify a user across every app in your project, regardless of how the user signs in...." so my question is, Is there a way to have firebase register users automatically after using SigninWithCustomToken? Can anyone advise on a correct flow to achieve sync between current back end and firebase users?
I´ve never used firebase before and have not found more than very basic documentation.
Thanks in advance.

Logging out with Google OAuth on iOS

I'm using Google's GTMAppAuth to prompt users to log in and authorize access to their Google account. That much is working, and API calls work as expected.
What's not working is logging out. In the GTMAppAuth code, removing authorization is handled by setting the GTMAppAuthFetcherAuthorization instance to nil, so that the app can't make API calls for the user account.
Except, when you reauthorize, Google's authorization flow does not require a password to get authorization back. It shows a list of previously used accounts and asks which one you want. If you choose on one, voila, you're in! No need for a password. I have to ask the user's permission, but what if it's a different user? They can get in to the previous user's account, and I need to prevent that. For my app this is not an unusual scenario.
So how do I really log out, so that a password would be required to reauthenticate? I'm setting my own GTMAppAuthFetcherAuthorization to nil, and I'm making sure to remove Google's keychain entries, but still no password is required.
In the end the only thing that does what I need is to load Google's "logout" page, as described in another answer. Basically, load https://www.google.com/accounts/Logout.
I had thought that the approach would be to revoke the app's OAuth tokens, but that's not actually what I need. I can revoke them, but Google will then issue another one without requiring a password (or it might be the same key-- it doesn't really matter to me if no password is required). I gather that this is based on browser cookies, but since I'm using SFSafariViewController on iOS I can't inspect the cookies. Revocation is a waste of time if tokens will be reissued like this.
Loading the logout page seems like kind of a hack but it has the useful effect of clearing out whatever browser state allows resuming access without requiring a password from the user.
On iOS this could produce an annoying UI artifact of displaying a web view when the user didn't expect one. But it's easy to prevent that by presenting the SFSafariViewController in a way that keeps the web view hidden. I did it like this, but there are other approaches.
func logout(presentingViewController:UIViewController?) -> Void {
guard let presentingViewController = presentingViewController else {
fatalError("A presenting view controller is required")
}
let logoutUrl = URL(string: "https://www.google.com/accounts/Logout")!
let logoutVC = SFSafariViewController(url: logoutUrl)
logoutVC.delegate = self
presentingViewController.addChildViewController(logoutVC)
presentingViewController.view.addSubview(logoutVC.view)
presentingViewController.view.sendSubview(toBack: logoutVC.view)
logoutVC.didMove(toParentViewController: presentingViewController)
// Remove our OAuth token
self.authorization = nil
}
The delegate assignment is important. In the delegate, I implemented this to dismiss the SFSafariViewController as soon as the logout page loads:
func safariViewController(_ controller: SFSafariViewController, didCompleteInitialLoad didLoadSuccessfully: Bool) {
controller.didMove(toParentViewController: nil)
controller.view.removeFromSuperview()
controller.removeFromParentViewController()
}
So I understand that you want the user to have to re-enter their password no matter what.
In that case a sub- optimal strategy of revoking the access tokens and disconnecting the app from given account could work. See: https://github.com/google/GTMAppAuth/issues/9 which leads you to https://developers.google.com/identity/protocols/OAuth2InstalledApp#tokenrevoke with their REST api because it's not natively supported in the library you are using.
Aside from that, a better strategy could be to consider the usage of the Cocoapods GoogleSignIn as they natively support the revoking feature. See: https://developers.google.com/identity/sign-in/ios/disconnect
Sidenote: Google's auth flow is designed that way so users can return to the app as quickly as possible, and since most people don't share their phones with others, you wouldn't really have to revoke their certificates.
Hope this helped! Good luck :)

How to check if user login to AWS Cognito for the first time?

I'm using mobile hub and Amazon Cognito to authenticate user by using Facebook provider. Once use login with Facebook I need to check if this is first time login to the app or not. If it is first time I need to get some information and if it is already sign-up to the app I need to get some information related to the user from dynamoDB. I was wondering what would be the best way to find out if user login to the app for the first time.
#import <AWSMobileHubHelper/AWSMobileHubHelper.h>
#implementation UserIdentityAccess
- (NSString *)getUserIdentity {
return [AWSIdentityManager defaultIdentityManager].identityId;
}
If you're already using Dynamo to store user metadata, you could potentially use that to store a flag on whether or not identity id x has been seen before.
Alternatively, Cognito Sync could be used here. You could put a record in a dataset that tracks if it's already been seen, then just check if it exists. One benefit this gives is it stores it against the identity id for you, so you don't have to deal with identity id to data mapping yourself. More information on Cognito sync is available here.

Use access token from GIDSignIn to use Google Drive SDK iOS

I have set up my project to sign in to a user's Google account using the Google Sign In framework. It works fine, but I want to use the access token that I get from the sign in to access the user's Google Drive. I am programming for iOS and have already set up the Drive SDK in my project. I feel like there should be a simple way of doing this. Thank You!
Recently experienced the same problem myself when attempting to use the Calendar API.
You can access the access token (and therefore use it in your URL Requests) like so:
if (GIDSignIn.sharedInstance().currentUser != nil) {
let accessToken = GIDSignIn.sharedInstance().currentUser.authentication.accessToken
// Use accessToken in your URL Requests Header
}
Make sure to only call this method after the user has signed in, the check for current user will prevent a crash from implicitly unwrapping a nil value.

Parse and Additional Facebook Permissions (iOS)

There are two Parse methods for reauthorizing a Facebook User (to gain additional permissions) in Parse (for iOS):
reauthorizeUser:withPublishPermissions:audience:block:
reauthorizeUser:withPublishPermissions:audience:target:selector:
Unfortunately, both of these methods are for publishPermissions. I am confused, because it seems that there is no way to add additional read permissions (i.e. Extended Profile Permissions) after the initial login.
Facebook advises that, when doing a general login (i.e. on app opening), you only ask for basic permissions, and then ask for extended permissions as needed, so as not to scare off the user.
So with Parse and Facebook for iOS, does this now mean that we need to ask for every single read permission that we may possibly need at initial login?
Overall it seems that the Parse documentation and framework seems to be lacking a lot of the Facebook instructions for login in various scenarios. We are directed to view the Facebook SDK, but everything there seems to apply to FBSession, and it is not clear which methods are replaced by Parse and which are needed in addition to Parse.
I, for example, have an app where the user can login to Parse via FB on app launch, but does not have to. If they do login, they are asked for only the basic permissions, as advised by FB. Then, should the user try to perform certain actions, they are asked for the permissions for that particular action. I have additional read permissions that need to be granted for the extended profile, as well as publish_actions.
Can anyone give me some direction in this case, or point me too a really thorough, up-to-date, example? The Parse FB Scrumptious example code looked promising to me at first, but it is severely outdated.
Thanks!
Apparently there are more than one way to do it. The easiest one I found using Parse for Android was like this:
Collection<String> publishPermissions = Arrays.asList("publish_actions");
ParseFacebookUtils.linkWithPublishPermissionsInBackground(user, myActivityOrFragment, publishPermissions, new SaveCallback() {...});
Which means that after logging in, you should call linkWithPublishPermissionsInBackground with your user reference and the new permission list. It will open a new Facebook window asking for that permission and link the result to your user.
This code I tested and it works. But seems that Parse is not that smart, some things it does automatically and some it does not. So after that you need to call something like:
ParseFacebookUtilities.linkInBackground(ParseUser, AccessToken)
To actually save it to the user on the server, otherwise, it would work only while the App is running.

Resources