[GH-ISSUE #549] Crash on using twitter as client and Webviews #363

Closed
opened 2026-03-03 16:48:04 +03:00 by kerem · 9 comments
Owner

Originally created by @sanchgoel on GitHub (Sep 30, 2019).
Original GitHub issue: https://github.com/OAuthSwift/OAuthSwift/issues/549

Description:

Crash after line super.handle(url) ... using WebView or WkWebView.

override func handle(_ url: URL) {
targetURL = url
super.handle(url)
self.loadAddressURL()
}

#Error In Xcode
'NSInvalidArgumentException', reason: 'Application tried to present modally an active controller <Influencer.TwitterViewController: 0x7f91ddf0b080>.'

Where TwitterViewController is the controller implementing OAuthViewController

OAuth Provider? (Twitter, Github, ..):

Twitter

OAuth Version:

  • Version 1
  • Version 2

OS (Please fill the version) :

  • iOS :
  • OSX :
  • TVOS :
  • WatchOS :

Installation method:

  • Carthage
  • CocoaPods
  • Swift Package Manager
  • Manually

Library version:

  • head
  • v2.0.0
  • v1.4.1
  • v1.2.1
  • v1.2 (Swift 4.0)
  • v1.0.0
  • v0.6
  • other: (Please fill in the version you are using.)

Xcode version:

  • 11.x (Swift 5.1)

  • 10.x (Swift 5.0)

  • 10.x (Swift 4.1)

  • 9.3 (Swift 4.1)

  • 9.0 (Swift 4.0)

  • other: (Please fill in the version you are using.)

  • objective c

Originally created by @sanchgoel on GitHub (Sep 30, 2019). Original GitHub issue: https://github.com/OAuthSwift/OAuthSwift/issues/549 ### Description: Crash after line super.handle(url) ... using WebView or WkWebView. override func handle(_ url: URL) { targetURL = url super.handle(url) self.loadAddressURL() } #Error In Xcode 'NSInvalidArgumentException', reason: 'Application tried to present modally an active controller <Influencer.TwitterViewController: 0x7f91ddf0b080>.' Where TwitterViewController is the controller implementing OAuthViewController ### OAuth Provider? (Twitter, Github, ..): Twitter ### OAuth Version: - [x] Version 1 - [ ] Version 2 ### OS (Please fill the version) : - [x] iOS : - [ ] OSX : - [ ] TVOS : - [ ] WatchOS : ### Installation method: - [ ] Carthage - [x] CocoaPods - [ ] Swift Package Manager - [ ] Manually ### Library version: - [ ] head - [x] v2.0.0 - [ ] v1.4.1 - [ ] v1.2.1 - [ ] v1.2 (Swift 4.0) - [ ] v1.0.0 - [ ] v0.6 - [ ] other: (Please fill in the version you are using.) ### Xcode version: - [x] 11.x (Swift 5.1) - [ ] 10.x (Swift 5.0) - [ ] 10.x (Swift 4.1) - [ ] 9.3 (Swift 4.1) - [ ] 9.0 (Swift 4.0) - [ ] other: (Please fill in the version you are using.) - [ ] objective c
kerem closed this issue 2026-03-03 16:48:04 +03:00
Author
Owner

@phimage commented on GitHub (Sep 30, 2019):

it depend on your application code. I cannot figure what append

you use OAuthWebViewController ? if yes try change value of useTopViewControlerInsteadOfNavigation
or put OAuthWebViewController as children of your controller

<!-- gh-comment-id:536576204 --> @phimage commented on GitHub (Sep 30, 2019): it depend on your application code. I cannot figure what append you use OAuthWebViewController ? if yes try change value of useTopViewControlerInsteadOfNavigation or put OAuthWebViewController as children of your controller
Author
Owner

@sanchgoel commented on GitHub (Oct 3, 2019):

Hey @phimage ... it worked, the webview was redirected to twitter ... login was done and twitter was given authorization. I was redirected to the url, i received token and verifier but i didn't get any callback in the authorize block.

let _ = oauthswift.authorize(
withCallbackURL: URL(string: "https://api-dev.kyral.app/callback/twitter")!) { result in
switch result {
case .success(let (_, _, _)):
self.testTwitter(oauthswift)
case .failure(let error):
print(error.description)
}
}

^ No callback received here.

Here test twitter is the method to get the timeline of twitter.

func testTwitter(_ oauthswift: OAuth1Swift) {
let stringUrl = "https://api.twitter.com/1.1/statuses/mentions_timeline.json"
let _ = oauthswift.client.get(stringUrl, parameters: [:]) { result in
switch result {
case .success(let response):
let jsonDict = try? response.jsonObject()
print(String(describing: jsonDict))
case .failure(let error):
print(error)
}
}
}

Can you please tell me a way by which i can hit this url after receiving oauth_token and oauth_verifier successfully? Or what did i do wrong that i didn't receive any callback in the authorize block.

Thanks!

<!-- gh-comment-id:537818359 --> @sanchgoel commented on GitHub (Oct 3, 2019): Hey @phimage ... it worked, the webview was redirected to twitter ... login was done and twitter was given authorization. I was redirected to the url, i received token and verifier but i didn't get any callback in the authorize block. let _ = oauthswift.authorize( withCallbackURL: URL(string: "https://api-dev.kyral.app/callback/twitter")!) { result in switch result { case .success(let (_, _, _)): self.testTwitter(oauthswift) case .failure(let error): print(error.description) } } ^ No callback received here. Here test twitter is the method to get the timeline of twitter. func testTwitter(_ oauthswift: OAuth1Swift) { let stringUrl = "https://api.twitter.com/1.1/statuses/mentions_timeline.json" let _ = oauthswift.client.get(stringUrl, parameters: [:]) { result in switch result { case .success(let response): let jsonDict = try? response.jsonObject() print(String(describing: jsonDict)) case .failure(let error): print(error) } } } Can you please tell me a way by which i can hit this url after receiving oauth_token and oauth_verifier successfully? Or what did i do wrong that i didn't receive any callback in the authorize block. Thanks!
Author
Owner

@phimage commented on GitHub (Oct 3, 2019):

did you pass now into handle(_ url: ? (put a breakpoint)
because handle will decode the url and call the callback passed in authorize

<!-- gh-comment-id:537936358 --> @phimage commented on GitHub (Oct 3, 2019): did you pass now into handle(_ url: ? (put a breakpoint) because handle will decode the url and call the callback passed in `authorize `
Author
Owner

@sanchgoel commented on GitHub (Oct 3, 2019):

@phimage i have implemented the handle method in my webviewcontroller

I tried putting a breakpoint here. i got the url in the handle method but i still didn't get any callback in the authorize block

class WKWebViewController: OAuthWebViewController {
  var webView: WKWebView!
  var targetURL: URL?
  
  override func viewDidLoad() {
    super.viewDidLoad()
  }
  
  override func handle(_ url: URL) {
    targetURL = url
    super.handle(url)
    loadAddressURL()
  }
  
  func loadAddressURL() {
    guard let url = targetURL else { return }
    let req = URLRequest(url: url)
    
    self.webView?.load(req)
  }
}

extension WKWebViewController: WKUIDelegate, WKNavigationDelegate {
  override func loadView() {
    let webConfiguration = WKWebViewConfiguration()
    webView = WKWebView(frame: .zero, configuration: webConfiguration)
    webView.allowsBackForwardNavigationGestures = true
    webView.uiDelegate = self
    webView.navigationDelegate = self
    view = webView
  }
  
  func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
    print("loaded")
  }
  
  func webView(_ webView: WKWebView,
               decidePolicyFor navigationAction: WKNavigationAction,
               decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
    // Check for OAuth Callback
    if let url = navigationAction.request.url, url.scheme == "oauth-swift" {
      UIApplication.shared.open(url, options: [:], completionHandler: nil)
      self.dismiss(animated: true, completion: nil)
      decisionHandler(.cancel)
      return
    }
    
    // Restrict URL's a user can access
    if let host = navigationAction.request.url?.host {
      if host.contains("twitter") {
        decisionHandler(.allow)
        return
      } else {
        // open link outside of our app
        checkRequestForCallbackURL(request: navigationAction.request)
        decisionHandler(.cancel)
        return
      }
    }
    
    decisionHandler(.cancel)
  }
  
  func checkRequestForCallbackURL(request: URLRequest) {
    if let requestURLString = (request.url?.absoluteString) {
      let oauthVerifierSeparatedArray = requestURLString.components(separatedBy: "&oauth_verifier=")
      if oauthVerifierSeparatedArray.count == 2 {
        let verifier = oauthVerifierSeparatedArray[1]
        let oauthTokenSeparatedArray = oauthVerifierSeparatedArray[0].components(separatedBy: "oauth_token=")
        let token = oauthTokenSeparatedArray[1]
        
        if let twitterVC = self.presentingViewController as? TwitterViewController {
          
          twitterVC.test(token: token, verifier: verifier)
          if let parentNav = twitterVC.presentingViewController as? UINavigationController {
            for controller in parentNav.children {
              if let superParent = controller as? LinkSocialAccountsViewController {
                superParent.dismiss(animated: true, completion: nil)
              }
            }
          }
        }
      }
    }
  }
}
<!-- gh-comment-id:537939567 --> @sanchgoel commented on GitHub (Oct 3, 2019): @phimage i have implemented the handle method in my webviewcontroller I tried putting a breakpoint here. i got the url in the handle method but i still didn't get any callback in the authorize block ``` class WKWebViewController: OAuthWebViewController { var webView: WKWebView! var targetURL: URL? override func viewDidLoad() { super.viewDidLoad() } override func handle(_ url: URL) { targetURL = url super.handle(url) loadAddressURL() } func loadAddressURL() { guard let url = targetURL else { return } let req = URLRequest(url: url) self.webView?.load(req) } } extension WKWebViewController: WKUIDelegate, WKNavigationDelegate { override func loadView() { let webConfiguration = WKWebViewConfiguration() webView = WKWebView(frame: .zero, configuration: webConfiguration) webView.allowsBackForwardNavigationGestures = true webView.uiDelegate = self webView.navigationDelegate = self view = webView } func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { print("loaded") } func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { // Check for OAuth Callback if let url = navigationAction.request.url, url.scheme == "oauth-swift" { UIApplication.shared.open(url, options: [:], completionHandler: nil) self.dismiss(animated: true, completion: nil) decisionHandler(.cancel) return } // Restrict URL's a user can access if let host = navigationAction.request.url?.host { if host.contains("twitter") { decisionHandler(.allow) return } else { // open link outside of our app checkRequestForCallbackURL(request: navigationAction.request) decisionHandler(.cancel) return } } decisionHandler(.cancel) } func checkRequestForCallbackURL(request: URLRequest) { if let requestURLString = (request.url?.absoluteString) { let oauthVerifierSeparatedArray = requestURLString.components(separatedBy: "&oauth_verifier=") if oauthVerifierSeparatedArray.count == 2 { let verifier = oauthVerifierSeparatedArray[1] let oauthTokenSeparatedArray = oauthVerifierSeparatedArray[0].components(separatedBy: "oauth_token=") let token = oauthTokenSeparatedArray[1] if let twitterVC = self.presentingViewController as? TwitterViewController { twitterVC.test(token: token, verifier: verifier) if let parentNav = twitterVC.presentingViewController as? UINavigationController { for controller in parentNav.children { if let superParent = controller as? LinkSocialAccountsViewController { superParent.dismiss(animated: true, completion: nil) } } } } } } } } ```
Author
Owner

@sanchgoel commented on GitHub (Oct 23, 2019):

@phimage Any suggestion?

<!-- gh-comment-id:545336546 --> @sanchgoel commented on GitHub (Oct 23, 2019): @phimage Any suggestion?
Author
Owner

@phimage commented on GitHub (Oct 23, 2019):

@sanchgoel did you respond to my question?

https://github.com/OAuthSwift/OAuthSwift#handle-url-in-appdelegate

<!-- gh-comment-id:545353661 --> @phimage commented on GitHub (Oct 23, 2019): @sanchgoel did you respond to my question? https://github.com/OAuthSwift/OAuthSwift#handle-url-in-appdelegate
Author
Owner

@sanchgoel commented on GitHub (Oct 23, 2019):

@phimage I have implemented handle url in app delegate
I am sorry i couldn't explain you my problem properly.

I implemented the twitter login using WKWebView. I am attaching the two files that i created for this ... Can you please see and let me know what i implemented wrong.

I am able to open the twitter login in webview ... then i am able to authorise the app ... I receive the oauth token and verifier from the redirected Url ... But i don't know how to get back to the callback in twitterViewController. Please have a look at the two files attached.

Or if you could suggest how can i call the twitter timeline api using the oauth token and verifier i received in the redirect url.

TwitterFiles.zip

Thanks for helping!

<!-- gh-comment-id:545376107 --> @sanchgoel commented on GitHub (Oct 23, 2019): @phimage I have implemented handle url in app delegate I am sorry i couldn't explain you my problem properly. I implemented the twitter login using WKWebView. I am attaching the two files that i created for this ... Can you please see and let me know what i implemented wrong. I am able to open the twitter login in webview ... then i am able to authorise the app ... I receive the oauth token and verifier from the redirected Url ... But i don't know how to get back to the callback in twitterViewController. Please have a look at the two files attached. Or if you could suggest how can i call the twitter timeline api using the oauth token and verifier i received in the redirect url. [TwitterFiles.zip](https://github.com/OAuthSwift/OAuthSwift/files/3761712/TwitterFiles.zip) Thanks for helping!
Author
Owner

@phimage commented on GitHub (Oct 23, 2019):

your callback url is https://api-dev.kyral.app/callback/twitter
but you keep code about "oauth-swift" url scheme let url = navigationAction.request.url, url.scheme == "oauth-swift"
Dit https://api-dev.kyral.app/callback/twitter redirect to oauth-swift://xxxx.? with token etc??

The app delegate code that must be executed is "OAuthSwift.handle(url: url)"
And IT IS my first question, did you put a breakpoint here...

if you implement as you say app delegate, you have that code

and it is because UIApplication.shared.open(url, options: [:], completionHandler: nil) will open oauth-swift:// and then the code in app delegate will be executed

if you cannot use url scheme because of your https://api-dev.kyral.app/callback/twitter
you check that the url match your one and make the same call that you can see here :
https://github.com/OAuthSwift/OAuthSwift/blob/1.4.1/Demo/Common/WebViewController.swift#L86
or call directly "OAuthSwift.handle(url: url)" to launch the callback

<!-- gh-comment-id:545426192 --> @phimage commented on GitHub (Oct 23, 2019): your callback url is https://api-dev.kyral.app/callback/twitter but you keep code about "oauth-swift" url scheme `let url = navigationAction.request.url, url.scheme == "oauth-swift"` Dit https://api-dev.kyral.app/callback/twitter redirect to oauth-swift://xxxx.? with token etc?? The app delegate code that must be executed is "OAuthSwift.handle(url: url)" And IT IS my first question, did you put a breakpoint here... if you implement as you say app delegate, you have that code and it is because ` UIApplication.shared.open(url, options: [:], completionHandler: nil)` will open oauth-swift:// and then the code in app delegate will be executed if you cannot use url scheme because of your https://api-dev.kyral.app/callback/twitter you check that the url match your one and make the same call that you can see here : https://github.com/OAuthSwift/OAuthSwift/blob/1.4.1/Demo/Common/WebViewController.swift#L86 or call directly "OAuthSwift.handle(url: url)" to launch the callback
Author
Owner

@sanchgoel commented on GitHub (Oct 23, 2019):

@phimage Yes it was not being called due to the https://api-dev.kyral.app/callback/twitter

It worked using the OAuthSwift.handle(url: url)

Thanks a lot!

<!-- gh-comment-id:545458948 --> @sanchgoel commented on GitHub (Oct 23, 2019): @phimage Yes it was not being called due to the https://api-dev.kyral.app/callback/twitter It worked using the OAuthSwift.handle(url: url) Thanks a lot!
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/OAuthSwift#363
No description provided.