Skip to content
Michael Lustig edited this page Jan 8, 2020 · 8 revisions

Alamofire v4 supports a new RequestRetrier protocol that works perfectly with OAuth2 v3. If you're stuck with an older Alamofire version you may try the old way of doing things.

See below for the OAuth2RequestRetrier class that you can drop into your project. Set up your OAuth2 instance as usual, without forgetting to implement handleRedirectURL() (step 3). Then instantiate one SessionManager and set its adapter and retrier, like so:

let sessionManager = SessionManager()
let retrier = OAuth2RetryHandler(oauth2: <# your OAuth2 instance #>)
sessionManager.adapter = retrier
sessionManager.retrier = retrier
self.alamofireManager = sessionManager   // you must hold on to this somewhere
// Note that the `validate()` call here is important
sessionManager.request("https://api.github.com/user").validate().responseJSON { response in
    debugPrint(response)
}

And here's OAuth2RetryHandler; if you use CocoaPods, use import p2_OAuth2 instead.

import Foundation
import OAuth2
import Alamofire


class OAuth2RetryHandler: RequestRetrier, RequestAdapter {
    
    let loader: OAuth2DataLoader
    
    init(oauth2: OAuth2) {
        loader = OAuth2DataLoader(oauth2: oauth2)
    }
    
    /// Intercept 401 and do an OAuth2 authorization.
    public func should(_ manager: SessionManager, retry request: Request, with error: Error, completion: @escaping RequestRetryCompletion) {
        if let response = request.task?.response as? HTTPURLResponse, 401 == response.statusCode, let req = request.request {
            var dataRequest = OAuth2DataRequest(request: req, callback: { _ in })
            dataRequest.context = completion
            loader.enqueue(request: dataRequest)
            loader.attemptToAuthorize() { authParams, error in
                guard error?.asOAuth2Error != .alreadyAuthorizing else {
                    // Don't dequeue requests if we are waiting for other authorization request
                    return
                }
                self.loader.dequeueAndApply() { req in
                    if let comp = req.context as? RequestRetryCompletion {
                        comp(nil != authParams, 0.0)
                    }
                }
            }
        }
        else {
            completion(false, 0.0)   // not a 401, not our problem
        }
    }
    
    /// Sign the request with the access token.
    public func adapt(_ urlRequest: URLRequest) throws -> URLRequest {
        guard nil != loader.oauth2.accessToken else {
            return urlRequest
        }
        return try urlRequest.signed(with: loader.oauth2)   // "try" added in 3.0.2
    }
}

That's it. Happy requesting!

Clone this wiki locally