Medium OAuth Client for iOS

Some time ago, my friend Monty and I considered integrating Medium API into our app, in.notes. At that time their API was relatively young and unpolished.

A couple of days ago I decide to take another look at it. What started as a single class with two functions for token retrieval turned into a full blown OAuth client with Keychain support. If you would rather skip the explanation and go straight to sample code, here it is!

I should mention that I tried keeping my implementation somewhat flexible to support other APIs. I agree that it would have been much better to work with at least two end points to map out similarities, my current implementation can be modded with relative ease in the future.

I begin with a protocol definition.

The above protocol defines data and behavior that’s usually needed when it comes to OAuth implementation. Things like appId, appSecret, redirectUri, responseType, as well as the authorize URL and the exchange request used to, well, exchange code for the actual token are all required.

Any type conforming to this protocol will supply its own data for use with our OAuth caller.

Next step is to build our Medium service.

As you can see, it’s a simple class named Medium that conforms to Service protocol. There are three properties that are unique to this request – scope (array of Scope), state and token – computed property (don’t mind it for now). Both the authorize and exhangeRequest functions use NSURLComponents class for constructing URLs. While I could have built both URLs as strings, this felt a bit cleaner and clearer especially when it comes to constructing query parameters.

Originally I decided that both functions will throw errors but then changed my mind and decided that crashing will make more sense. If you think about the use case, the client is written for developers, there will be no input from the user which means that once tested and implemented, everything should work as expected. If NSURLComponents instance cannot return a valid URL, the developer should deal with it right away – hence the crash.

Next, let’s build a simple OAuth caller.

The only thing this class is responsible for is making authorization call and then exchanging accepted code for the token. Speaking of which, here is the model object for our token:

My model object knows how to initialize itself with JSON response from Medium API. It also knows how to encode and decode itself. This will be especially useful when it comes to storing a complete token (scope, expiration, refreshToken) in the Keychain instead of a single string – accessToken. For this to work, I need to write a few extensions for my Token model object as well as NSURLResponse and String.

The NSURLResponse extension is something picked up from Branton – my good friend from Smart Sheets. The other two extensions are for simplifying certain tasks like getting substring (note, it would probably be good to have this function throw when the index is outside of the bound of the length of the string) and converting an array of Scope objects into a string used for constructing authorization query.

Last piece of the puzzle is writing code for storing token in the keychain.

Keychain is a simple wrapper for storing any object conforming to NSCoding as password in the keychain. This concludes the actual implementation. Let’s take a look at how we should use this in our application.

When you need to login, simply make the OAuth call like this:

Pretty neat. The entire token object will be stored securely in the keychain and used for authenticated calls.

Medium OAuth Client for iOS