Reputation: 70976
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.
Upvotes: 1
Views: 1300
Reputation: 70976
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()
}
Upvotes: 2
Reputation: 518
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 :)
Upvotes: 1