title: Facebook manual login flow with Wkwebview fails in macOS App
body: <p><code>WKWebView</code> doesn't do the &quot;login from Facebook&quot; job as wanted, because the browser seems to always remember the account credentials previously used to login, even though I tried to clear cookies both before and after the login requests are made.</p>
  <p>I'm manually building a Facebook login flow for a MacOS project, following the guide here:</p>
  <p><a href="https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow/" rel="nofollow noreferrer">https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow/</a></p>
  <p>I decided to use a embedded web browser (<code>WKWebView</code>) to handle the login. What I wanted to achieve is that, when user clicks on the &quot;log in from Facebook&quot; button, the <code>WKWebView</code> gets presented as a sheet, loads the  <a href="https://www.facebook.com/v3.3/dialog/oauth?client_id=%5Bmy-app-id%5D&amp;redirect_uri=https://www.facebook.com/connect/login_success.html&amp;response_type=token" rel="nofollow noreferrer">https://www.facebook.com/v3.3/dialog/oauth?client_id=[my-app-id]&amp;redirect_uri=https://www.facebook.com/connect/login_success.html&amp;response_type=token</a> request, shows the dialog to let the user enter his email and password, and, after the user successfully logs in and the it gets the <code>redirect_uri</code> with a token, closes itself to finish the login flow.</p>
  <p>For the first time this procedure gets executed on a new computer, it works fine. But once I successfully login as one user, the browser seems to automatically remember the account credentials, and next time I click on &quot;log in from Facebook&quot;, it shows and then closes immediately, which means that it directly jumps to the redirect_uri with the previous user's token appended to the uri.</p>
  <hr />
  <p>I don't have much prior knowledge about how program works with caches or how it stores user credentials, but I assumed it has something to do with cookies. So I did</p>
  <pre><code>HTTPCookieStorage.shared.removeCookies(since: .distantPast)
  </code></pre>
  <p>and</p>
  <pre><code>facebookLoginRequest.httpShouldHandleCookies = false
  </code></pre>
  <p>at where I think is suitable.</p>
  <p>These operations made a difference but still don't solve the problem. The browser doesn't close itself &quot;right after&quot; it's presented any more, but still, it might get the redirect-uri with the token of the previous user after 10-ish seconds and then closes itself (interrupting the ongoing credential entering behavior of the current user) and logs into my app as the previous user.</p>
  <hr />
  <p>I then inspected what requests the program was loading (how it jumps between url's), and here it is:</p>
  <pre><code>1. https://www.facebook.com/v3.3/dialog/oauth?client_id=2390673297883518&amp;redirect_uri=https:// www.facebook.com/connect/login_success.html&amp;response_type=token
  2. https://www.facebook.com/login.php?skip_api_login=1&amp;api_key=2390673297883518&amp;kid_directed_site=0&amp;app_id=2390673297883518&amp;signed_next=1&amp;next=https%3A%2F%2Fwww.facebook.com%2Fv3.3%2Fdialog%2Foauth%3Fclient_id%3D2390673297883518%26redirect_uri%3Dhttps%253A%252F%252Fwww.facebook.com%252Fconnect%252Flogin_success.html%26response_type%3Dtoken%26ret%3Dlogin%26fbapp_pres%3D0%26logger_id%3Da6eb9f6e-66d4-41e3-a5f2-dc995c98183e&amp;cancel_url=https%3A%2F%2Fwww.facebook.com%2Fconnect%2Flogin_success.html%3Ferror%3Daccess_denied%26error_code%3D200%26error_description%3DPermissions%2Berror%26error_reason%3Duser_denied%23_%3D_&amp;display=page&amp;locale=en_US
  3. https://www.facebook.com/common/referer_frame.php
  4. https://www.facebook.com/v3.3/dialog/oauth?client_id=2390673297883518&amp;redirect_uri=https%3A%2F%2Fwww.facebook.com%2Fconnect%2Flogin_success.html&amp;response_type=token&amp;ret=login&amp;fbapp_pres=0&amp;logger_id=a6eb9f6e-66d4-41e3-a5f2-dc995c98183e
  5. https://www.facebook.com/login/device-based/regular/login/?login_attempt=1&amp;next=https%3A%2F%2Fwww.facebook.com%2Fv3.3%2Fdialog%2Foauth%3Fclient_id%3D2390673297883518%26redirect_uri%3Dhttps%253A%252F%252Fwww.facebook.com%252Fconnect%252Flogin_success.html%26response_type%3Dtoken%26ret%3Dlogin%26fbapp_pres%3D0%26logger_id%3Da6eb9f6e-66d4-41e3-a5f2-dc995c98183e&amp;lwv=100
  6. https://www.facebook.com/v3.3/dialog/oauth?client_id=2390673297883518&amp;redirect_uri=https%3A%2F%2Fwww.facebook.com%2Fconnect%2Flogin_success.html&amp;response_type=token&amp;ret=login&amp;fbapp_pres=0&amp;logger_id=fa7e695e-3469-43f5-9b79-75c6130824b0&amp;ext=1564027752&amp;hash=AebnuofbfCPezaKn
  7. https://www.facebook.com/connect/login_success.html#access_token=EAAXXXX&amp;data_access_expiration_time=1571800153&amp;expires_in=5104236
  </code></pre>
  <p>1, 2, 3 always take place. 4 is what's loaded when the browser interrupts you, automatically logs you as the previous user, and closes itself. It doesn't always happen, or at least it doesn't always happen after the same amount of time, so it's pretty unpredictable to me. I think it might have something to do with clearing cookies, but I don't know how.</p>
  <p>If 4 is loaded, 5 and 6 never gets to get loaded, and we directly jump to 7 (that has the access token of the previous user), which is what should be loaded after a complete, successful login.</p>
  <hr />
  <p>Then what I did was trying to block 4.</p>
  <pre><code>if let urlStr = navigationAction.request.url?.absoluteString {
          let block = urlStr.range(of: &quot;&amp;ret=login&amp;fbapp_pres=0&amp;logger_id=&quot;)
          let allow = urlStr.range(of: &quot;&amp;hash=&quot;)
          if (block != nil &amp;&amp; allow == nil) {
              print(&quot;not ok&quot;)
              print(urlStr)
              decisionHandler(.cancel)
          }  else {
              print(&quot;should ok&quot;)
              print(urlStr)
              decisionHandler(.allow)
          }
  </code></pre>
  <p>So 4 never gets loaded. I got to complete the &quot;entering my email and password and click the login button&quot; action every time. But this still doesn't solve the problem, as, like a little fewer than half of all times, after I click on login, Facebook gives the following message: &quot;Something went wrong. Try closing the browser and reopen it.&quot; Then I'll have to quit my application and reopen it, and sometimes it works fine, sometimes it still doesn't, so I'll need to quit and reopen and again.</p>
  <p>When I click on the login button, 5 always gets loaded. But when it succeeds, 6 and 7 also gets loaded; when it fails, it gets stuck at 5, doesn't get to 6 and 7, and pops up the &quot;something went wrong&quot; message.</p>
  <p>Ccreen shot of the something went wrong message:</p>
  <p><a href="https://i.stack.imgur.com/B5fgh.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/B5fgh.png" alt="enter image description here" /></a></p>
  <p>As you can see in the screen shot, under the &quot;something went wrong&quot; message, my Facebook home page is also loaded. However, the loaded Facebook page doesn't necessarily belong to the user whose credential I just entered before I clicked on login but to the previous user (I tested using multiple accounts). If the loaded Facebook home page and the user who just tried to login mismatch, Facebook can detect this mismatch and then pop up a &quot;please login first&quot; message and force the user back to a login dialog.</p>
  <p>This means that even though I tried to block 4, it didn't really prevent the program from logging itself in as the previous user; it probably only prevented the URL from loading and displaying in the user interface. I also searched online and it's said that the &quot;something went wrong&quot; message is shown when a user is already logged in but another login request is made again.</p>
  <p>So I guess the core problem that's troubling me is still, how on earth can I get the program to stop storing the credentials of the previous user? How does this storing mechanism even work? Thanks so much in advance for anyone who would help me with solving this problem. I have poor networking knowledge and what happens here after the initial HTTP request was made looks like a big black box to me and I feel hopeless lol</p>
  <p>Here's the entire class I've written to try to handle the login flow for reference:</p>
  <pre><code>import Cocoa
  import WebKit
  
  class signInWeb: NSViewController, WKNavigationDelegate {
  
  
  var token = &quot;&quot;
  var gotToken = false
  static var instance : signInWeb?
  var request : URLRequest?
  
  
  override func viewDidLoad() {
      super.viewDidLoad()
      // Do view setup here.
      self.view.setFrameSize(NSSize.init(width: 1200, height: 900))
  
      let urlString = NSString(format: NSString.init(string : &quot;https://www.facebook.com/v3.3/dialog/oauth?client_id=%@&amp;redirect_uri=%@&amp;response_type=token&quot;), Facebook.AppId, &quot;https://www.facebook.com/connect/login_success.html&quot;) as String
      let facebookUrl = URL(string: urlString)
      var facebookLoginRequest = URLRequest.init(url: facebookUrl!)
      self.request = facebookLoginRequest
      
      
      HTTPCookieStorage.shared.removeCookies(since: .distantPast)
      facebookLoginRequest.httpShouldHandleCookies = false
      
      
      signInWebView.load(facebookLoginRequest)
      signInWebView.navigationDelegate = self
      
      let loadedColor = ColorGetter.getCurrentThemeColor()
      
      backButton.font = .labelFont(ofSize: 15)
      if loadedColor != ThemeColor.white {
          backButton.setText(str: &quot;Back&quot;, color: loadedColor)
      } else {
          backButton.setText(str: &quot;Back&quot;, color: .black)
      }
      
      signInWeb.instance = self
  }
  
  
  @IBOutlet weak var signInWebView: WKWebView!
  
  
  
  func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -&gt; Void) {
      //HTTPCookieStorage.shared.removeCookies(since: .distantPast)
      
      if let urlStr = navigationAction.request.url?.absoluteString {
          let block = urlStr.range(of: &quot;&amp;ret=login&amp;fbapp_pres=0&amp;logger_id=&quot;)
          let allow = urlStr.range(of: &quot;&amp;hash=&quot;)
          if (block != nil &amp;&amp; allow == nil) {
              print(&quot;not ok&quot;)
              print(urlStr)
              decisionHandler(.cancel)
          }  else {
              print(&quot;should ok&quot;)
              print(urlStr)
              decisionHandler(.allow)
          }
          let components = urlStr.components(separatedBy: &quot;#access_token=&quot;)
          if components.count &gt;= 2 {
              let secondHalf = components[1]
              let paramComponents = secondHalf.components(separatedBy: &quot;&amp;&quot;)
              let token = paramComponents[0]
              self.token = token
              gotToken = true
              let parent = self.parent as! SignIn
              parent.handleCollapse()
          }
          
      }
      
  }
  
  @IBAction func goBack(_ sender: HoverButton) {
      let parent = self.parent as! SignIn
      parent.handleCollapse()
  }
  
  
  @IBOutlet weak var backButton: HoverButton!
  func changeButtonColor(color : NSColor) {
      if color != ThemeColor.white {
          backButton.setText(str: &quot;Back&quot;, color: color)
      } else {
          backButton.setText(str: &quot;Back&quot;, color: .black)
      }
  }
  }
  </code></pre>