JohnnyD
JohnnyD

Reputation: 188

Firebase Twitter oAuth callback not working for Swift ios13

I have followed the instructions on https://firebase.google.com/docs/auth/ios/twitter-login to a T for Swift and I get the web popup to authorise the App I created on Twitter Dev, the callback is called and then the webview sits on an empty page of about:blank. Nothing can be done but click the Done button which then results in a Error Domain=FIRAuthErrorDomain Code=17058 "The interaction was cancelled by the user." Callback address is correct. I've used the Twitter Consumer API Keys as the keys to enter in the Firebase console.

What am I missing?

Upvotes: 4

Views: 2044

Answers (6)

Invalid declaration of the OAuthProvider can be issue but, for me problem was that FirebaseAppDelegateProxyEnabled was set to false. You can simply solve that by setting FirebaseAppDelegateProxyEnabled to true, but if you want to have that proxy disabled you can do that but you need to add Auth.auth().canHandle(url) to the func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) method in SceneDelegate (for iOS 13+) and everything will work without problem.

Upvotes: 1

tommy
tommy

Reputation: 41

Got stucked in about:blank page for days, tried all the above but not working, solved by add following code in AppDelegate

func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
    let twitterhandeled = Auth.auth().canHandle(url)
    return twitterhandeled
}

Upvotes: 2

remarcoble
remarcoble

Reputation: 683

I found my solution looking at @tommy's answer.

If you're developing a SwiftUI app just add to your top level view:

.onOpenURL { url in
    Auth.auth().canHandle(url) // Required for twitter login callback
}

Probably if your app is not using SwiftUI then @tommy code should work:

// Inside your AppDelegate
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
    let twitterhandeled = Auth.auth().canHandle(url)
    return twitterhandeled
}

Upvotes: 2

Konstantin
Konstantin

Reputation: 307

For me there was no need in framework modifications.

As stated in a issue on GitHub: provider property should be

declared at a class or global level

So I just moved its initialisation out of a function.

Before:

class AuthViewController: UIViewController {
   private func signIn() {
      let provider = OAuthProvider(providerID: "twitter.com")
      provider.getCredentialWith(nil) { 
         ...
      }
   }
}

After:

class AuthViewController: UIViewController {
   private let provider = OAuthProvider(providerID: "twitter.com")
   private func signIn() {
      provider.getCredentialWith(nil) { 
         ...
      }
   }
}

Upvotes: 3

Vitalii K
Vitalii K

Reputation: 61

For everyone who still has an issue with getting callback working, I managed to fix it. Sadly, you have to edit the method in the library (not the best way, but still. Bug was reported to firebase team). The method should look like the one below (you can find it in the file named FIROAuthProvider.m, line 125. I intentionally left commented lines, so you see the problem there... Hope it helps somebody :)

- (void)getCredentialWithUIDelegate:(nullable id<FIRAuthUIDelegate>)UIDelegate
                         completion:(nullable FIRAuthCredentialCallback)completion {
  if (![FIRAuthWebUtils isCallbackSchemeRegisteredForCustomURLScheme:self->_callbackScheme]) {
    [NSException raise:NSInternalInconsistencyException
                format:@"Please register custom URL scheme '%@' in the app's Info.plist file.",
                       self->_callbackScheme];
  }
//  __weak __typeof__(self) weakSelf = self;
//  __weak FIRAuth *weakAuth = _auth;
//  __weak NSString *weakProviderID = _providerID;
  dispatch_async(FIRAuthGlobalWorkQueue(), ^{
    FIRAuthCredentialCallback callbackOnMainThread =
        ^(FIRAuthCredential *_Nullable credential, NSError *_Nullable error) {
          if (completion) {
            dispatch_async(dispatch_get_main_queue(), ^{
              completion(credential, error);
            });
          }
        };
    NSString *eventID = [FIRAuthWebUtils randomStringWithLength:10];
    NSString *sessionID = [FIRAuthWebUtils randomStringWithLength:10];
//    __strong __typeof__(self) strongSelf = weakSelf;
    [self
        getHeadFulLiteURLWithEventID:eventID
                           sessionID:sessionID
                          completion:^(NSURL *_Nullable headfulLiteURL, NSError *_Nullable error) {
                            if (error) {
                              callbackOnMainThread(nil, error);
                              return;
                            }
                            FIRAuthURLCallbackMatcher callbackMatcher =
                                ^BOOL(NSURL *_Nullable callbackURL) {
                                  return [FIRAuthWebUtils
                                      isExpectedCallbackURL:callbackURL
                                                    eventID:eventID
                                                   authType:kAuthTypeSignInWithRedirect
                                             callbackScheme:self->_callbackScheme];
                                };
//                            __strong FIRAuth *strongAuth = weakAuth;
                            [_auth.authURLPresenter
                                     presentURL:headfulLiteURL
                                     UIDelegate:UIDelegate
                                callbackMatcher:callbackMatcher
                                     completion:^(NSURL *_Nullable callbackURL,
                                                  NSError *_Nullable error) {
                                       if (error) {
                                         callbackOnMainThread(nil, error);
                                         return;
                                       }
                                       NSString *OAuthResponseURLString =
                                           [self OAuthResponseForURL:callbackURL
                                                                     error:&error];
                                       if (error) {
                                         callbackOnMainThread(nil, error);
                                         return;
                                       }
                                       __strong NSString *strongProviderID = _providerID;
                                       FIROAuthCredential *credential = [[FIROAuthCredential alloc]
                                               initWithProviderID:strongProviderID
                                                        sessionID:sessionID
                                           OAuthResponseURLString:OAuthResponseURLString];
                                       callbackOnMainThread(credential, nil);
                                     }];
                          }];
  });
}

Upvotes: 6

JohnnyD
JohnnyD

Reputation: 188

Ok so I resolved this question but not entirely sure how now. I believe it was because the callback wasn't being issued and thus not picked up by the app. The callback wasn't issue due to the authentication and I believe because I hadn't created the terms of service and privacy policy. So make sure you have done that in the Twitter dev page.

In the twitter dev page, the callback link is: https://yourApp.firebaseapp.com/__/auth/handler You'll find this in your firebase authentication settings when you enable twitter.

Ensure you have in info.plist LSApplicationQueriesSchemes an array of: twitter twitterauth

In your swift file:

var provider = OAuthProvider(providerID: "twitter.com")

Your button action:

@IBAction func onCustonTwitterButtonPressed(_ sender: Any) {
    MyAppsCoreServicesScripts.logoutSocial() // My logout routine.
    provider.getCredentialWith(nil) { credential, error in
    if let error = error {
        MyAppsCoreServicesScripts.showError(prefix: "Twitter Login",error: error, showMsg: true)
        } else if credential != nil {
            self.firebaseLogin(credential!)            
        }
    }
}

Good luck! Hope this helps someone.

Upvotes: 0

Related Questions