4. Authenticate your operations
5m

Overview

We're logged into our app, but we haven't put our authorization token to work yet!

In this lesson, we will:

  • Introduce Interceptors
  • Implement an ApolloInterceptor class
  • Finalize the logic to include our authorization token with all requests

Introducing Apollo iOS Interceptors

In order to actually book a trip, we need to pass our authentication token along to the server. To understand how we can do that, let's first dig a little deeper into how 's ApolloClient works.

To send to a , ApolloClient uses a class called RequestChainNetworkTransport. This class (the default implementation of the NetworkTransport protocol) handles HTTP communication with the server by generating a RequestChain object for each request.

A RequestChain consists of a sequence of interceptors—special objects that can operate upon the request that passes through them. They can mutate the request, check the cache before the request hits the network, and even do additional work after a response is received from the server.

A diagram showing the request passing through an array of interceptors that make up the request chain, before going to the server

Actually creating the RequestChain, the array of interceptors, is a job for an InterceptorProvider. We get a few providers out of the box by default; one, the DefaultInterceptorProvider, returns a fairly standard array of interceptors.

A diagram showing the interceptors that make up the request chain provided by the default interceptor provider

This default sequence of interceptors represents the "chain" that each request passes through on its way to the . But we can also take matters into our own hands: adding our own interceptors to the chain anywhere we need to perform custom actions. In this case, we want to include an interceptor that adds our token to .

A diagram showing how we can add a custom interceptor to the sequence of default interceptors

Note: To read more about this pattern, see Request Chain Customization in the Apollo docs.

We'll bring this custom logic into our application in a few steps.

  1. First, we'll create our AuthorizationInterceptor. This job of this class will be to add our authorization token (if one is available) to the headers of every request that passes through it.
  2. Next, we'll create a a new InterceptorProvider for our app to use. This provider will make sure that our new interceptor is included as part of the request chain that every request passes through.
  3. Then we'll hook up our new InterceptorProvider to our app!

1. Create AuthorizationInterceptor

First up: creating the interceptor that will add our authorization token to a request's headers.

Go to File > New > File... and create a new Swift file called AuthorizationInterceptor.swift. (Make sure it's added to the RocketReserver target.)

A screenshot of our IDE, adding a new file called AuthorizationInterceptor that we add to our app's target

Open that file, and add the following code:

AuthorizationInterceptor.swift
import Foundation
import Apollo
import ApolloAPI
class AuthorizationInterceptor: ApolloInterceptor {
public var id: String = UUID().uuidString
func interceptAsync<Operation>(
chain: RequestChain,
request: HTTPRequest<Operation>,
response: HTTPResponse<Operation>?,
completion: @escaping (Result<GraphQLResult<Operation.Data>, Error>) -> Void
) where Operation : GraphQLOperation {
// TODO
}
}

Next, we'll import KeychainSwift at the top of the file so we can access the key we stored in the keychain in the last step of the tutorial:

AuthorizationInterceptor.swift
import Foundation
import Apollo
import ApolloAPI
+ import KeychainSwift

Then, we'll replace the TODO within the interceptAsync method with code to get the token from the keychain, and add it to our headers if it exists:

AuthorizationInterceptor.swift
let keychain = KeychainSwift()
if let token = keychain.get(LoginView.loginKeychainKey) {
request.addHeader(name: "Authorization", value: token)
}
chain.proceedAsync(
request: request,
response: response,
interceptor: self,
completion: completion
)

Our app is already configured to use the DefaultInterceptorProvider: it's the class that creates the RequestChain consisting of the array of interceptors each request should flow through.

We still want to use the DefaultInterceptorProvider's request chain (it provides a lot of helpful interceptors, after all!), but we also want to make sure that our new AuthorizationInterceptor runs before all the other interceptors in the chain. We can achieve this by subclassing the DefaultInterceptorProvider class, and inserting our new interceptor at the start of the chain.

Create NetworkInterceptorProvider

Go to File > New > File... and create a new Swift file called NetworkInterceptorProvider.swift. (Make sure it's added to the RocketReserver target.)

Add the following code to insert the AuthorizationInterceptor before the other interceptors provided by the DefaultInterceptorProvider:

NetworkInterceptorProvider.swift
import Foundation
import Apollo
import ApolloAPI
class NetworkInterceptorProvider: DefaultInterceptorProvider {
override func interceptors<Operation>(for operation: Operation) -> [ApolloInterceptor] where Operation : GraphQLOperation {
var interceptors = super.interceptors(for: operation)
interceptors.insert(AuthorizationInterceptor(), at: 0)
return interceptors
}
}

Note: Another way to do this would be to copy and paste the list interceptors provided by the DefaultInterceptorProvider (which are all public), and then place our custom interceptors in the points in the array where we want them. But because we just want to place our custom interceptor at the front of the list, it's simpler to subclass.

Use the interceptor

Next, return to the Network class. Replace the ApolloClient with an updated lazy var which creates the RequestChainNetworkTransport manually, using your custom interceptor provider:

Network.swift
class Network {
static let shared = Network()
- private(set) lazy var apollo = ApolloClient(url: URL(string: "https://apollo-fullstack-tutorial.herokuapp.com/graphql")!)
+ private(set) lazy var apollo: ApolloClient = {
+ let client = URLSessionClient()
+ let cache = InMemoryNormalizedCache()
+ let store = ApolloStore(cache: cache)
+ let provider = NetworkInterceptorProvider(client: client, store: store)
+ let url = URL(string: "https://apollo-fullstack-tutorial.herokuapp.com/graphql")!
+ let transport = RequestChainNetworkTransport(interceptorProvider: provider, endpointURL: url)
+
+ return ApolloClient(networkTransport: transport, store: store)
+ }()
}

Great! Now, let's return to AuthorizationInterceptor.swift. Click on the line numbers to add a breakpoint at the line where we've instantiated the Keychain:

AuthorizationInterceptor.swift
let keychain = KeychainSwift()

Build and run the application. Whenever a network request goes out, that breakpoint should now get hit. If we're logged in, our token will be sent to the server whenever we make a request!

A screenshot of our IDE with a breakpoint added where we instantiate keychain

Now let's make sure that we remove the breakpoint going forward.

Task!

Up next

Now that our are being authenticated, it's time to define additional to book and cancel trips.

Previous

Share your questions and comments about this lesson

This course is currently in

beta
. Your feedback helps us improve! If you're stuck or confused, let us know and we'll help you out. All comments are public and must follow the Apollo Code of Conduct. Note that comments that have been resolved or addressed may be removed.

You'll need a GitHub account to post below. Don't have one? Post in our Odyssey forum instead.