With the release of Swift 5 and Alamofire 5, the method of implementing Moya + Oauth 2.0 has also changed slightly. The overall framework still follows the content of the previous article, only updating some content that needs to be handled.
1. Alamofire part
Alamofire has deprecated SessionManager, favoring Session, so the related code needs to be modified:
func getManager() -> SessionManager {
let oauth2 = OAuth2CodeGrant(settings: [
"client_id": "my_swift_app",
"client_secret": "C7447242",
"authorize_uri": "https://github.com/login/oauth/authorize",
"token_uri": "https://github.com/login/oauth/access_token", // code grant only
"redirect_uris": ["myapp://oauth/callback"], // register your own "myapp" scheme in Info.plist
"scope": "user repo:status",
"secret_in_body": true, // Github needs this
"keychain": false, // if you DON'T want keychain integration
] as OAuth2JSON)
let oauthHandler = OAuth2Handler(oauth2: oauth2)
let interceptor = Interceptor(adapter: oauthHandler, retrier: oauthHandler)
let session = Alamofire.Session(interceptor: interceptor)
return session
}
2. Oauth part
Modify OAuth2Handler
code, since the protocal singature of RequestRetrier
and RequestAdapter
had been changed, so we need to implementing them both:
extension OAuth2Handler: RequestRetrier {
func retry(_ request: Request, for session: Session, dueTo error: Error, completion: @escaping (RetryResult) -> Void) {
if let response = request.task?.response as? HTTPURLResponse, response.statusCode == 401, let req = request.request {
var dataRequest = OAuth2DataRequest(request: req, callback: { _ in })
dataRequest.context = completion
loader.enqueue(request: dataRequest)
loader.attemptToAuthorize { authParams, _ in
self.loader.dequeueAndApply { req in
if let comp = req.context as? ((RetryResult) -> Void) {
let result = (authParams != nil) ? RetryResult.retry : RetryResult.doNotRetry
comp(result)
}
}
}
} else {
completion(.doNotRetry)
}
}
}
extension OAuth2Handler: RequestAdapter {
func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result) -> Void) {
guard loader.oauth2.accessToken != nil else {
completion(.failure(NSError(domain:"", code:0, userInfo:nil)))
return
}
if let signedRequest = try? urlRequest.signed(with: loader.oauth2) {
completion(.success(signedRequest))
} else {
completion(.failure(NSError(domain:"", code:0, userInfo:nil)))
}
}
}
3. Catalyst part
The existing solution can be directly applied to the Catalyst project, but in my actual test, I found that iOS projects (iPhone/iPad) can make normal requests, while macOS can authenticate successfully but cannot make normal requests after authentication. After troubleshooting, I found that it was because the Oauth token was saved using Keychain: “keychain”: true, if you want to use it in macOS, you need to turn on “Keychain Sharing”.