Safariviewcontroller: How to Grab Oauth Token from Url

SafariViewController: How to grab OAuth token from URL?

Figured it out. Some of the methods were pre iOS 9 and now deprecated. I also had the application function in the ViewController I created when it should have been defined in the AppDelagate.swift. For example

Added at end of AppDelegate.swift

func application(app: UIApplication, openURL url: NSURL, options: [String : AnyObject]) -> Bool {

print("app: \(app)")
// print OAuth response URL
print("url: \(url)")
print("options: \(options)")

if let sourceApplication = options["UIApplicationOpenURLOptionsSourceApplicationKey"] {
if (String(sourceApplication) == "com.testApp.Incognito") {
NSNotificationCenter.defaultCenter().postNotificationName(kSafariViewControllerCloseNotification, object: url)
return true
}
}
return true
}

ViewController.swift

import SafariServices

let kSafariViewControllerCloseNotification = "kSafariViewControllerCloseNotification"

// facebook OAuth URL
let authURL = NSURL(string: "https://www.facebook.com/dialog/oauth?client_id=3627644767&redirect_uri=https://www.facebook.com/connect/login_success.html&scope=basic_info,email,public_profile,user_about_me,user_activities,user_birthday,user_education_history,user_friends,user_interests,user_likes,user_location,user_photos,user_relationship_details&response_type=token")

class ViewController: UIViewController, SFSafariViewControllerDelegate {

var safariVC: SFSafariViewController?
@IBOutlet weak var loginButton: UIButton!

@IBAction func loginButtonTapped(sender: AnyObject) {
safariVC = SFSafariViewController(URL: authURL!)
safariVC!.delegate = self
self.presentViewController(safariVC!, animated: true, completion: nil)
}

override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(ViewController.safariLogin(_:)), name: kSafariViewControllerCloseNotification, object: nil)
}

func safariLogin(notification: NSNotification) {
// get the url from the auth callback
let url = notification.object as! NSURL
// Finally dismiss the Safari View Controller with:
self.safariVC!.dismissViewControllerAnimated(true, completion: nil)
}

override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}

func safariViewControllerDidFinish(controller: SFSafariViewController) {
controller.dismissViewControllerAnimated(true) { () -> Void in
print("You just dismissed the login view.")
}
}

func safariViewController(controller: SFSafariViewController, didCompleteInitialLoad didLoadSuccessfully: Bool) {
print("didLoadSuccessfully: \(didLoadSuccessfully)")

}
}

open url function not called in AppDelegate when trying to grab token from oauth url

So it was actually a mixture of things that I did not notice...

  1. The URL I was trying to use there was wrong: It should not be
    http:// but yourApp:// since you want yourApp to handle the
    callback. On some forum I read that Strava only allows http redirect
    uris, which made me try it that way, but that's actually wrong, as
    the documentation states:

URL to which the user will be redirected with the authorization code, must be to the callback domain associated with the application, or its sub-domain, localhost and 127.0.0.1 are white-listed.

And we got to the next thing, namely:


  1. You should check what you name your application on the Strava admin page at Settings/My Api Application.
    Following the yourApp example, it should be something like this:
    Strava My Api Application setup

(My mistake was, that I did not provide a valid/matching callback domain.)


  1. Finally, your plist file should be also set accordingly:
        <key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string>com.yourdomain.yourApp</string>
<key>CFBundleURLSchemes</key>
<array>
<string>yourApp</string>
</array>
</dict>
</array>

And it works like charm: it does not actually matter if it's iOS 9 or 11, or you use SFSafariViewController VS you leave the app with UIApplication.shared.openURL() etc...

Good luck ;)

Swift OAuth2.0 with redirectURI

If you are targeting iOS 13 you can use the new AuthenticationServices library provided by Apple.

It will work on both macOS and iOS.

Maybe this would help other developers, I create a simple and small swift package to handle OAuth2 in Swift, you can check the demo project it works very well /p>

https://github.com/hadiidbouk/SimpleOAuth2

Edit:

You are passing the wrong URLs, they should be like this

let request: OAuth2Request = .init(authUrl: "https://stackoverflow.com/oauth",
tokenUrl: "https://stackoverflow.com/oauth/access_token/json",
clientId: "<<your client id>>",
redirectUri: "redirect-uri://stackexchange.com",
clientSecret: "<<your client secret>>",
scopes: ["private_info"])

Can I get cookies from Safari in a SFSafariViewController?

REQUIREMENTS

So it seems you want a solution to invoke secured web content from a mobile app, and to avoid an extra login. It is a common requirement and I will be adding some stuff to my blog on this topic over the next month or so.

STATE OF THE INDUSTRY

The problem with the above is that third party cookies, such as those issued by Identity Providers, are often dropped by default these days due to browser security initiatives such as Intelligent Tracking Prevention changes - which is ON by default in Safari:

Sample Image

COOKIE PROPERTIES

Worth checking that your cookies are issued with SameSite=None, which will give you the best options for a third party cookie based solution.

MOBILE FIRST DESIGNS

In an OAuth world, in order to meet the requirements, it is likely to be necessary to send a token from the mobile UI to the web UI, which of course has prerequisites that need to be designed for:

  • Web UI must use tokens
  • Web UI must use different strategies for token handling depending on the host

OPTION 1

One option is to use a mobile web view to show the web content - see my code below:

  • Web UI Code to ask the host for tokens
  • Mobile UI Code to service these requests

OPTION 2

Another option is to send something representing the token in a query string parameter from the mobile app to the Web UI, in which case you need to ensure that:

  • No usable tokens are recorded in web server logs
  • The token has a one time use only

A typical implementation would look like this:

  • Mobile UI calls an /api/token/encrypt endpoint
  • API stores a token hash in a database and returns an encrypted value with a short time to live
  • Token is sent from the Mobile App to the Web UI
  • Web UI calls an /api/token/decrypt endpoint to get the real token
  • The API's decrypt implementation deletes the database entry

Handle completion if no success when opening url with SafariViewController

I don't think SFSafariViewController provides much interaction/feedback with your app.

As per Apple documentation:

The user's activity and interaction with SFSafariViewController are
not visible to your app, which cannot access AutoFill data, browsing
history, or website data.

Choosing the Best Web Viewing Class

If your app lets users view
websites from anywhere on the Internet, use the SFSafariViewController
class. If your app customizes, interacts with, or controls the display
of web content, use the WKWebView class.

As Apple suggests, you may want to take a look at WKWebView class.



Related Topics



Leave a reply



Submit