Authentication
Authentication can be tricky. There are a few ways network requests can be authenticated. Let’s discuss two of the common ones.
Basic HTTP Auth
HTTP auth is a username/password challenge built into the HTTP protocol
itself. If you need to use HTTP auth, you can provide a CredentialsPlugin
when initializing your provider.
let provider = MoyaProvider<YourAPI>(plugins: [CredentialsPlugin { _ -> URLCredential? in
return URLCredential(user: "user", password: "passwd", persistence: .none)
}
])
This specific examples shows a use of HTTP that authenticates every request, which is usually not necessary. This might be a better idea:
let provider = MoyaProvider<YourAPI>(plugins: [CredentialsPlugin { target -> URLCredential? in
switch target {
case .targetThatNeedsAuthentication:
return URLCredential(user: "user", password: "passwd", persistence: .none)
default:
return nil
}
}
])
Access Token Auth
Another common method of authentication is by using an access token.
Moya provides an AccessTokenPlugin
that supports both Bearer
authentication
using a JWT and Basic
authentication for API keys.
Also there is support for custom authorization types.
There are two steps required to start using an AccessTokenPlugin
.
You need to add an
AccessTokenPlugin
to yourMoyaProvider
like this:let token = "eyeAm.AJsoN.weBTOKen" let authPlugin = AccessTokenPlugin { _ in token } let provider = MoyaProvider<YourAPI>(plugins: [authPlugin])
The
AccessTokenPlugin
initializer accepts atokenClosure
that is responsible for returning the token to be applied to the header of the request.Your
TargetType
needs to conform to theAccessTokenAuthorizable
protocol:
extension YourAPI: TargetType, AccessTokenAuthorizable {
case targetThatNeedsBearerAuth
case targetThatNeedsBasicAuth
case targetThatNeedsCustomAuth
case targetDoesNotNeedAuth
var authorizationType: AuthorizationType? {
switch self {
case .targetThatNeedsBearerAuth:
return .bearer
case .targetThatNeedsBasicAuth:
return .basic
case .targetThatNeedsCustomAuth:
return .custom("CustomAuthorizationType")
case .targetDoesNotNeedAuth:
return nil
}
}
}
The AccessTokenAuthorizable
protocol requires you to implement a single
property, authorizationType
, which is an enum representing the header to
use for the request.
Bearer HTTP Auth Bearer requests are authorized by adding a HTTP header of the following form:
Authorization: Bearer <token>
Basic API Key Auth Basic requests are authorized by adding a HTTP header of the following form:
Authorization: Basic <token>
Custom API Key Auth Custom requests are authorized by adding a HTTP header of the following form:
Authorization: <Custom> <token>
OAuth
OAuth is quite a bit trickier. It involves a multi step process that is often different between different APIs. You really don’t want to do OAuth yourself – there are other libraries to do it for you. Heimdallr.swift, for example. The trick is just getting Moya and whatever you’re using to talk to one another.
Moya is built with OAuth in mind. Signing
a network request with OAuth can
itself sometimes require network requests be performed first, so signing
a request for Moya is an asynchronous process. Let’s see an example.
let requestClosure = { (endpoint: Endpoint, done: URLRequest -> Void) in
let request = try! endpoint.urlRequest() // This is the request Moya generates
YourAwesomeOAuthProvider.signRequest(request, completion: { signedRequest in
// The OAuth provider can make its own network calls to sign your request.
// However, you *must* call `done()` with the signed so that Moya can
// actually send it!
done(.success(signedRequest))
})
}
let provider = MoyaProvider<YourAPI>(requestClosure: requestClosure)
(Note that Swift is able to infer the YourAPI
generic – neat!)
Handle session refresh in your Provider subclass
You can take a look at example of session refreshing before each request in Examples/SubclassingProvider. It is based on Artsy’s networking implementation.