How to Sign Out of Google After Being Authenticated

后端 未结 6 982
伪装坚强ぢ
伪装坚强ぢ 2021-02-06 23:54

So my app has the option to sign in with Google. Upon clicking the button that Google provides, a web view opens and has the user input their credentials. After allowing the app

6条回答
  •  日久生厌
    2021-02-07 00:01

    Why doesn't the user need to renter their password after signing out?

    I wanted to give some clarity to why the user instantly signs back in and why some of these solutions don't work on iOS 13.

    The following does in fact sign the user out of your app:

    GIDSignIn.sharedInstance().signOut()
    

    But it does not sign the user out from google in Safari itself!! Try this for yourself, sign into a google account in your app. Sign out from the app and then go to accounts.google.com in your Safari browser, the account will still be signed in! So the cookies are being shared with the default Safari browser but why?

    After investigating a little bit I found this in the OIDExternalUserAgentiOS class that handles the actual interactive auth flow.

      // iOS 12 and later, use ASWebAuthenticationSession
      if (@available(iOS 12.0, *)) {
        // ASWebAuthenticationSession doesn't work with guided access (rdar://40809553)
        if (!UIAccessibilityIsGuidedAccessEnabled()) {
          __weak OIDExternalUserAgentIOS *weakSelf = self;
          NSString *redirectScheme = request.redirectScheme;
          ASWebAuthenticationSession *authenticationVC =
              [[ASWebAuthenticationSession alloc] initWithURL:requestURL
                                            callbackURLScheme:redirectScheme
                                            completionHandler:^(NSURL * _Nullable callbackURL,
                                                                NSError * _Nullable error) {
            __strong OIDExternalUserAgentIOS *strongSelf = weakSelf;
            if (!strongSelf) {
                return;
            }
            strongSelf->_webAuthenticationVC = nil;
            if (callbackURL) {
              [strongSelf->_session resumeExternalUserAgentFlowWithURL:callbackURL];
            } else {
              NSError *safariError =
                  [OIDErrorUtilities errorWithCode:OIDErrorCodeUserCanceledAuthorizationFlow
                                   underlyingError:error
                                       description:nil];
              [strongSelf->_session failExternalUserAgentFlowWithError:safariError];
            }
          }];
    #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000
          if (@available(iOS 13.0, *)) {
              authenticationVC.presentationContextProvider = self;
          }
    #endif
          _webAuthenticationVC = authenticationVC;
          openedUserAgent = [authenticationVC start];
        }
      }
      // iOS 11, use SFAuthenticationSession
      if (@available(iOS 11.0, *)) {
        // SFAuthenticationSession doesn't work with guided access (rdar://40809553)
        if (!openedUserAgent && !UIAccessibilityIsGuidedAccessEnabled()) {
          __weak OIDExternalUserAgentIOS *weakSelf = self;
          NSString *redirectScheme = request.redirectScheme;
          SFAuthenticationSession *authenticationVC =
              [[SFAuthenticationSession alloc] initWithURL:requestURL
                                         callbackURLScheme:redirectScheme
                                         completionHandler:^(NSURL * _Nullable callbackURL,
                                                             NSError * _Nullable error) {
            __strong OIDExternalUserAgentIOS *strongSelf = weakSelf;
            if (!strongSelf) {
                return;
            }
            strongSelf->_authenticationVC = nil;
            if (callbackURL) {
              [strongSelf->_session resumeExternalUserAgentFlowWithURL:callbackURL];
            } else {
              NSError *safariError =
                  [OIDErrorUtilities errorWithCode:OIDErrorCodeUserCanceledAuthorizationFlow
                                   underlyingError:error
                                       description:@"User cancelled."];
              [strongSelf->_session failExternalUserAgentFlowWithError:safariError];
            }
          }];
          _authenticationVC = authenticationVC;
          openedUserAgent = [authenticationVC start];
        }
      }
      // iOS 9 and 10, use SFSafariViewController
      if (@available(iOS 9.0, *)) {
        if (!openedUserAgent && _presentingViewController) {
          SFSafariViewController *safariVC =
              [[SFSafariViewController alloc] initWithURL:requestURL];
          safariVC.delegate = self;
          _safariVC = safariVC;
          [_presentingViewController presentViewController:safariVC animated:YES completion:nil];
          openedUserAgent = YES;
        }
      }
      // iOS 8 and earlier, use mobile Safari
      if (!openedUserAgent){
        openedUserAgent = [[UIApplication sharedApplication] openURL:requestURL];
      }
    

    If you are on iOS 12+ it uses ASWebAuthenticationService, which shares cookies with Safari by default! For iOS 11, 10, 9, 8 it's a similar situation with different execution methods. Also something interesting I found in Apple documentation here about SFSafariViewController:

    In iOS 9 and 10, it [SFSafariViewController] shares cookies and other website data with Safari.

    When the google sign in page appears, it shares cookies with Safari. This is why we aren't being signed out of google completely. In fact, this seems to be completely intentional.

    How do we sign out the user?

    This works for all iOS versions that GIDSignIn supports:

    let url = URL(string: "https://accounts.google.com/Logout")!
    UIApplication.shared.open(url, options: [:], completion: nil)
    

    Unfortunately this redirects the user outside the app. But you can explain the necessity in an UIAlertController before calling open.

提交回复
热议问题