21
21
22
22
import UIKit
23
23
import SafariServices
24
+ import AuthenticationServices
24
25
#if !NO_MODULE_IMPORT
25
26
import Base
26
27
#endif
@@ -39,6 +40,8 @@ open class OAuth2Authorizer: OAuth2AuthorizerUI {
39
40
/// Used to store the `SFSafariViewControllerDelegate`.
40
41
private var safariViewDelegate : AnyObject ?
41
42
43
+ /// Used to store the authentication session.
44
+ private var authenticationSession : AnyObject ?
42
45
43
46
public init ( oauth2: OAuth2 ) {
44
47
self . oauth2 = oauth2
@@ -72,23 +75,31 @@ open class OAuth2Authorizer: OAuth2AuthorizerUI {
72
75
- parameter at: The authorize URL to open
73
76
*/
74
77
public func authorizeEmbedded( with config: OAuth2AuthConfig , at url: URL ) throws {
75
- guard let controller = config. authorizeContext as? UIViewController else {
76
- throw ( nil == config. authorizeContext) ? OAuth2Error . noAuthorizationContext : OAuth2Error . invalidAuthorizationContext
77
- }
78
-
79
- if #available( iOS 9 , * ) , config. ui. useSafariView {
80
- let web = try authorizeSafariEmbedded ( from: controller, at: url)
81
- if config. authorizeEmbeddedAutoDismiss {
82
- oauth2. internalAfterAuthorizeOrFail = { wasFailure, error in
83
- web. dismiss ( animated: true )
78
+ if #available( iOS 11 , * ) , config. ui. useAuthenticationSession {
79
+ guard let redirect = oauth2. redirect else {
80
+ throw OAuth2Error . noRedirectURL
81
+ }
82
+
83
+ authenticationSessionEmbedded ( at: url, withRedirect: redirect)
84
+ } else {
85
+ guard let controller = config. authorizeContext as? UIViewController else {
86
+ throw ( nil == config. authorizeContext) ? OAuth2Error . noAuthorizationContext : OAuth2Error . invalidAuthorizationContext
87
+ }
88
+
89
+ if #available( iOS 9 , * ) , config. ui. useSafariView {
90
+ let web = try authorizeSafariEmbedded ( from: controller, at: url)
91
+ if config. authorizeEmbeddedAutoDismiss {
92
+ oauth2. internalAfterAuthorizeOrFail = { wasFailure, error in
93
+ web. dismiss ( animated: true )
94
+ }
84
95
}
85
96
}
86
- }
87
- else {
88
- let web = try authorizeEmbedded ( from : controller , at : url )
89
- if config . authorizeEmbeddedAutoDismiss {
90
- oauth2 . internalAfterAuthorizeOrFail = { wasFailure , error in
91
- web . dismiss ( animated : true )
97
+ else {
98
+ let web = try authorizeEmbedded ( from : controller , at : url )
99
+ if config . authorizeEmbeddedAutoDismiss {
100
+ oauth2 . internalAfterAuthorizeOrFail = { wasFailure , error in
101
+ web . dismiss ( animated : true )
102
+ }
92
103
}
93
104
}
94
105
}
@@ -104,6 +115,47 @@ open class OAuth2Authorizer: OAuth2AuthorizerUI {
104
115
open func willPresent( viewController: UIViewController , in naviController: UINavigationController ? ) {
105
116
}
106
117
118
+ // MARK: - SFAuthenticationSession / ASWebAuthenticationSession
119
+
120
+ /**
121
+ Use SFAuthenticationSession or ASWebAuthenticationSession to manage authorisation.
122
+
123
+ On iOS 11, use SFAuthenticationSession. On iOS 12+, use ASWebAuthenticationSession.
124
+
125
+ The mechanism works just like when you're using Safari itself to log the user in, hence you **need to implement**
126
+ `application(application:openURL:sourceApplication:annotation:)` in your application delegate.
127
+
128
+ This method dismisses the view controller automatically - this cannot be disabled.
129
+
130
+ - parameter at: The authorize URL to open
131
+ - returns: A Boolean value indicating whether the web authentication session starts successfully.
132
+ */
133
+ @available ( iOS 11 . 0 , * )
134
+ @discardableResult
135
+ public func authenticationSessionEmbedded( at url: URL , withRedirect redirect: String ) -> Bool {
136
+ let completionHandler : ( URL ? , Error ? ) -> Void = { url, error in
137
+ if let url = url {
138
+ do {
139
+ try self . oauth2. handleRedirectURL ( url as URL )
140
+ }
141
+ catch let err {
142
+ self . oauth2. logger? . warn ( " OAuth2 " , msg: " Cannot intercept redirect URL: \( err) " )
143
+ }
144
+ } else {
145
+ self . oauth2. didFail ( with: nil )
146
+ }
147
+ self . authenticationSession = nil
148
+ }
149
+
150
+ if #available( iOS 12 , * ) {
151
+ authenticationSession = ASWebAuthenticationSession ( url: url, callbackURLScheme: redirect, completionHandler: completionHandler)
152
+ return ( authenticationSession as! ASWebAuthenticationSession ) . start ( )
153
+ } else {
154
+ authenticationSession = SFAuthenticationSession ( url: url, callbackURLScheme: redirect, completionHandler: completionHandler)
155
+ return ( authenticationSession as! SFAuthenticationSession ) . start ( )
156
+ }
157
+ }
158
+
107
159
108
160
// MARK: - Safari Web View Controller
109
161
@@ -135,13 +187,14 @@ open class OAuth2Authorizer: OAuth2AuthorizerUI {
135
187
web. preferredControlTintColor = tint
136
188
}
137
189
web. modalPresentationStyle = oauth2. authConfig. ui. modalPresentationStyle
138
-
190
+
139
191
willPresent ( viewController: web, in: nil )
140
192
controller. present ( web, animated: true , completion: nil )
141
193
142
194
return web
143
195
}
144
196
197
+
145
198
/**
146
199
Called from our delegate, which reacts to users pressing "Done". We can assume this is always a cancel as nomally the Safari view
147
200
controller is dismissed automatically.
0 commit comments