Last active
July 13, 2020 03:51
-
-
Save yesleon/904d8fe418a17467aada5b8661dba665 to your computer and use it in GitHub Desktop.
A wrapper around ASWebAuthenticationSession and SFAuthenticationSession.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// Usage: | |
// | |
// Facebook: | |
// | |
// 1. Follow this guide (WITHOUT setting up a URL scheme in Xcode): | |
// https://github.com/fullstackreact/react-native-oauth/issues/76#issuecomment-335902057 | |
// | |
// 2. call startFacebookAuthenticationSession(appID:completionHandler:) on a window: | |
// | |
// view.window?.startFacebookAuthenticationSession(appID: "{app-id}") { | |
// switch $0 { | |
// case .success(let token): | |
// print(token) | |
// case .failure(let error): | |
// print(error) | |
// } | |
// } | |
// | |
// | |
// Dropbox: | |
// | |
// view.window?.startDropboxAuthenticationSession( | |
// appKey: "{app-id}", | |
// callbackURI: "{redirect-uri}" | |
// ) { | |
// switch $0 { | |
// case .success(let token): | |
// print(token) | |
// case .failure(let error): | |
// print(error) | |
// } | |
// } | |
import UIKit | |
import AuthenticationServices | |
import SafariServices | |
@available(iOS 11.0, *) | |
extension UIWindow: ASWebAuthenticationPresentationContextProviding { | |
// MARK: - Core methods | |
@available(iOS 13.0, *) | |
public func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor { | |
self | |
} | |
// Unified interface for ASWebAuthenticationSession and SFAuthenticationSession. | |
func startAuthenticationSession( | |
url: URL, | |
callbackURLScheme: String?, | |
completionHandler: @escaping (URL?, Error?) -> Void | |
) { | |
if #available(iOS 12.0, *) { | |
var session: ASWebAuthenticationSession? | |
session = ASWebAuthenticationSession(url: url, callbackURLScheme: callbackURLScheme) { url, error in | |
completionHandler(url, error) | |
session = nil | |
} | |
if #available(iOS 13.0, *) { | |
session?.presentationContextProvider = self | |
} | |
session?.start() | |
} else { | |
var session: SFAuthenticationSession? | |
session = SFAuthenticationSession(url: url, callbackURLScheme: callbackURLScheme) { url, error in | |
completionHandler(url, error) | |
session = nil | |
} | |
session?.start() | |
} | |
} | |
func startImplicitGrantFlowAuthenticationSession( | |
endpoint: URL, | |
clientID: String, | |
callbackURI: String, | |
completionHandler: @escaping (Result<String, Error>) -> Void | |
) { | |
let state = UUID().uuidString | |
var urlComponents = URLComponents(url: endpoint, resolvingAgainstBaseURL: true)! | |
urlComponents.queryItems = [ | |
.init(name: "client_id", value: clientID), | |
.init(name: "response_type", value: "token"), | |
.init(name: "redirect_uri", value: callbackURI), | |
.init(name: "state", value: state) | |
] | |
let callbackURLScheme = String(callbackURI.prefix(while: { $0 != ":" })) | |
startAuthenticationSession(url: urlComponents.url!, callbackURLScheme: callbackURLScheme) { url, error in | |
if let error = error { | |
completionHandler(.failure(error)) | |
} else if let url = url { | |
var urlComponents = URLComponents(string: url.absoluteString) | |
let query = urlComponents?.fragment | |
urlComponents?.query = query | |
let queryItems = urlComponents?.queryItems | |
guard queryItems?.first(where: { $0.name == "state" })?.value == state else { fatalError() } | |
let token = queryItems?.first(where: { $0.name == "access_token" })?.value | |
completionHandler(.success(token!)) | |
} | |
} | |
} | |
// MARK: - Convenience methods | |
func startDropboxAuthenticationSession( | |
appKey: String, | |
callbackURI: String, | |
completionHandler: @escaping (Result<String, Error>) -> Void | |
) { | |
startImplicitGrantFlowAuthenticationSession( | |
endpoint: URL(string: "https://www.dropbox.com/oauth2/authorize")!, | |
clientID: appKey, | |
callbackURI: callbackURI, | |
completionHandler: completionHandler | |
) | |
} | |
func startFacebookAuthenticationSession( | |
appID: String, | |
completionHandler: @escaping (Result<String, Error>) -> Void | |
) { | |
startImplicitGrantFlowAuthenticationSession( | |
endpoint: URL(string: "https://www.facebook.com/v7.0/dialog/oauth")!, | |
clientID: appID, | |
callbackURI: "fb\(appID)://authorize", | |
completionHandler: completionHandler | |
) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment