OAuth2, Django-RestFramework and iOS RestKit

Recently I implemented an OAuth2 authentication scheme on a REST API, I couldn’t find any nice examples of how to use this in iOS, so here’s what I did.

Django OAuth2 provider

To get Django RestFramework to play nicely, we need to configure a couple of things. First, install django-oauth2-provider

pip install django-oauth2-provider

And add it to your INSTALLED_APPS:

    # ...

Add the routes to your urls:

url(r'^oauth2/', include('provider.oauth2.urls', namespace = 'oauth2')),

And create the tables

$ python manage.py syncdb
$ python manage.py migrate

Now you can create a client, with a token and secret in the admin. You’ll need this info later for the authentication part.

Django RestFramework

As I wanted to still be able to use my Basic Authentication, I appended the OAuth class to the default authenticators. This is not necessary, but I wanted the change to be backwards compatible. Be aware that this might be a security issue (as you can work around the OAuth2 authentication), so be aware of that.


And you’re all set. You should now be able to call the token endpoint with your credentials:

$ curl -X POST -d "client_id=YOUR_CLIENT_ID&client_secret=YOUR_CLIENT_SECRET&grant_type=password&username=YOUR_USERNAME&password=YOUR_PASSWORD" http://localhost:8000/oauth2/access_token/

and get a token in return:

{"access_token": "<your-access-token>", "scope": "read", "expires_in": 86399, "refresh_token": "<your-refresh-token>"}


Add AFOAuth2Client to your CocoaPods file:

pod 'AFOAuth2Client', '~> 0.1.2'

AFOAuth2Client is a simple layer on top of AFNetworking, so it’s quite easy to setup, once you know how.

In your App Delegate (or wherever you want to check the given credentials, say a LoginViewController), add this:

AFOAuth2Client *oauthClient = [AFOAuth2Client clientWithBaseURL:baseURL clientID:API_CLIENTID secret:API_SECRET];
[oauthClient authenticateUsingOAuthWithPath:@"/oauth2/token/"
    success:^(AFOAuthCredential *credential) {
        NSLog(@"I haz a token! %@", credential.accessToken);
        [AFOAuthCredential storeCredential:credential withIdentifier:oauthClient.serviceProviderIdentifier];
        [oauthClient setAuthorizationHeaderWithToken:credential.accessToken];
    failure:^(NSError *error) {
        NSLog(@"Error: %@", error);

// assign the oauthclient to the default manager
RKObjectManager *objectManager = [[RKObjectManager alloc] initWithHTTPClient:oauthClient];
[oauthClient setDefaultHeader:@"Accept" value:RKMIMETypeJSON];

API_CLIENTID and API_SECRET are the credentials you created in the backend. The endpoint path should be good if you followed along.

Now, whenever you make a RestKit call, it will use the token you requested above. The only pitfall I noticed is that this call is asynchronous, so you need to check if there already is a token available, before calling any other request. I ended up pushing a message to my MasterView, which refreshed the tableview using the new token.