Basic Authentication with a NSURLRequest in Cocoa Touch

While working on a certain unnamed iPhone app lately I ran across the need to use basic authentication in communication with REST services. For something that seems to be such a fundamental need for mobile applications I figured most of the work would be done for me. Turns out that's not the case. A few details are left up to you, the Cocoa Touch programmer.

What Basic Authentication is

In order to implement basic authentication in Cocoa Touch it is important to understand how it works. Basic authentication tokens are essentially formatted into a string in the format:

username:password

They are then Base64-encoded and formatted into an "Authorization" HTTP header who's value looks like:

Basic c2NvdHQ6dGlnZXI=

where "c2NvdHQ6dGlnZXI=" is the encoded token pair and "Basic" is a hard-coded prependage.

Easy enough right? Encode username and password, slap it in the header and make the request.

What's not Provided by Cocoa Touch: Base64

I thought for sure I'd be able to leverage something out-of-the-box to handle the Base64 encoding. Surely I can do it by using some simple method or function somewhere. It'd just be a one-liner something-er-other, right? Right?? Wrong!

Nothing in Cocoa Touch natively provides you with Base64 encoding capabilities. You also don't have access to openssl on the iPhone via the SDK. In Cocoa Touch's defense I guess it never claimed to have the batteries included (my python & ruby soaked brain always expects everything to be done for me;)).

While I've seen suggestions to statically link openssl against your iPhone app it's not only overkill but presumably puts the responsibility on you to comply with U.S. export regulations (the cryptography in openssl is legally a munition in the states after all).

Besides, it's rather simple to implement Base64 yourself.

A Base64 Implementation

There are a number of implementations you can cherry-pick from elsewhere but in the spirit of demonstration I'll provide an example Base64 encoder that you can use in your project.

Contrary to the spirit of demonstration, however, I'm not going to explain it too much as it's not the subject of the post. If you need more background about the algorithm Ramkumar Menon wrote an excellent blog post about it.

static char *alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-";

@implementation Base64
    +(char *)encode:(NSData *)plainText {
        // create an adequately sized buffer for the output.  every 3 bytes 
        // become four basically with padding to the next largest integer
        // divisible by four. 
        char * encodedText = malloc((((([plainText length] % 3) +
            [plainText length]) / 3) * 4) + 1);
        char* inputBuffer = malloc([plainText length]);
        inputBuffer = (char *)[plainText bytes];
    
        NSInteger i;
        NSInteger j = 0;
    
        // encode, this expands every 3 bytes to 4
        for(i = 0; i < [plainText length]; i += 3) {
            encodedText[j++] = alphabet[(inputBuffer[i] & 0xFC) >> 2];
            encodedText[j++] = alphabet[((inputBuffer[i] & 0x03) << 4)
                | ((inputBuffer[i + 1] & 0xF0) >> 4)];
    
            if(i + 1 >= [plainText length])
                // padding
                encodedText[j++] = '=';
            else 
                encodedText[j++] = alphabet[((inputBuffer[i + 1] & 0x0F) << 2)
                | ((inputBuffer[i + 2] & 0xC0) >> 6)];
    
            if(i + 2 >= [plainText length])
                // padding
                encodedText[j++] = '=';
            else
                encodedText[j++] = alphabet[inputBuffer[i + 2] & 0x3F];
        }
        
        // terminate the string
        encodedText[j] = 0;
    
        return outputBuffer;
    }
@end

Creating and Using a Proper Request

Now that we're ready to speak the encoding that the webservers are expecting we can get down to business. Consider the following code which executes an authenticated request against a resource via a synchronous NSURLRequest. Adding an "Authorization" header with the appropriately formatted, Base64-encoded authentication tokens are all that's required to authenticate the request.

NSURL *url = [NSURL URLWithString:@"http://127.0.0.1/"];
NSString userName = @"scott";
NSString password = @"tiger";

NSError *myError = nil;

// create a plaintext string in the format username:password
NSMutableString *loginString = (NSMutableString*)[@"" stringByAppendingFormat:@"%@:%@", userName, password];

// employ the Base64 encoding above to encode the authentication tokens
char *encodedLoginData = [Base64 encode:[loginString dataUsingEncoding:NSUTF8StringEncoding]];

// create the contents of the header 
NSString *authHeader = [@"Basic " stringByAppendingFormat:@"%@", 
    [NSString stringWithCString:encodedLoginData length:strlen(encodedLoginData)]];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL: url
    cachePolicy: NSURLRequestReloadIgnoringCacheData  
    timeoutInterval: 3];   

// add the header to the request.  Here's the $$$!!!
[request addValue:authHeader forHTTPHeaderField:@"Authorization"];

// perform the reqeust
NSURLResponse *response;

NSData *data = [NSURLConnection  
    sendSynchronousRequest: request  
    returningResponse: &response  
    error: &myError];  
*error = myError;

// POW, here's the content of the webserver's response.
NSString *result = [NSString stringWithCString:[data bytes] length:[data length]];

Conclusion

Aside from rolling-your-own (or snagging-someone-elses) Base64 implementation this isn't too bad.

To take it further you might employ NSURLCredential for storage of your authentication tokens.

Also if an asynchronous NSMutableURLRequest is used you can easily handle a webserver issuing a challenge by implementing the didReceiveAuthenticationChallenge message.

Created on 2010-01-24 13:50:00
Share on Facebook Facebook
Comment Feed
Add a Comment: (HTML not accepted. URLs will automatically be converted to links)
Body
Nickname (Login || Register)
Home Page
Email Addy(kept private)
Are you human?
Tags:
linq .Net performance sql 2008 sql server powershell indexes scripting reporting services filestream ruby ironruby entity framework EF testing .net framework 4.0 ADO.NET SSRS rs setpolicies vb cte c# podcasts webdav exchange server data warehousing Data Services Web Services Astoria jQuery database object oriented cql refactoring remoting simpledb cloud HTML GObject GNOME Vala BI couchdb django ORM python erlang functional C curl stackless concurrency Groovy Java JVM dynamic tools windows ironpython dlr systems programming go CAPTCHA appengine natural language full-text rails lucene wave clr parallel virtualization Oracle iPhone xml Objective-C Haiku security cocoa touch C++ BeOS Operating Systems Lucene monitoring Solr lisp VS 2010
Blog History:
Solrnet, a Solr Client Library for .Net - 03/08/2010
Monitoring Solr with LucidGaze - 02/21/2010
Haiku, an Open Source Continuation of BeOS - 02/10/2010
Basic Authentication with a NSURLRequest in Cocoa Touch - 01/24/2010
Asynchronous Programming in Cocoa Touch - 01/17/2010
NSXML-like XPath Support in Cocoa Touch with TouchXML - 01/03/2010
Using Solr in Django for Full-Text Searching via Solango - 01/01/2010
Using Entity Framework with Oracle - 12/22/2009
Solutions to Common VirtualBox Problems - 12/20/2009
Parallel Programming with the Task Parallel Library and PLINQ in .Net 4.0 - 12/14/2009
Clojure, A Lisp for the JVM and CLR - 12/13/2009
Google Wave Robots in Java - 12/07/2009
Employing Solr/Lucene with SQL Server for Full-Text Searching - 12/05/2009
Full-Text Indexing in Ruby Using Ferret - 11/28/2009
Home-Brewing a Full-Text Search in Google's AppEngine - 11/22/2009
Using reCAPTCHA With Django - 11/21/2009
Phat Go Code Launched - 11/19/2009
A Little More of Google's Go - 11/17/2009
First Impressions of Go, Google's New Systems Language - 11/14/2009
Scripting Your .Net Applications with IronPython - 11/03/2009
Windows Services in Python - 11/02/2009
My Tool List - 10/26/2009
Groovy: Dynamic Language for the JVM... Groovy! - 10/23/2009
Easy Concurrency with Stackless Python - 10/03/2009
C from erlang via linked-in driver - 09/16/2009
Templating with NDjango - 09/06/2009
A little bit o' Erlang - 08/23/2009
Tale of a Website, from Rails to ASP.NET to Django - 08/20/2009
Now in Django - 08/19/2009
Stored Procedures in Django - 08/09/2009
CouchDBExtension - 08/06/2009
POCO Entities in ADO.NET 4.0 - 07/30/2009
Accessing SimpleDB from SSRS - 07/22/2009
Easy GNOME Development with the Vala Programming Language - 07/16/2009
HTML Parsing with Ruby and Nokogiri - 07/12/2009
Amazon SimpleDB Batched PUTs Usage and Performance - 07/10/2009
PowerShell 2.0 Out-GridView, ISE and ScriptCmdlets - 07/05/2009
Asynchronous and remote execution with powershell 2 ctp3 - 06/30/2009
Understanding Source Code with NDepend and CQL - 06/22/2009
Object Oriented Databases with db4o - 06/07/2009
ADO.Net Data Services with jQuery - 05/29/2009
Exchange webdav automation - 05/26/2009
Podcasts - 05/26/2009
Linq to Object Performance - 05/11/2009
SQL 2008 and powershell - 01/25/2009
SQL 2008 filtered indexes - 06/11/2008
SQL 2008's table valued parameters - 05/11/2008
SQL 2008's MERGE statement - 04/22/2008
ironruby - 04/11/2008
SSRS scripting with RS.EXE - 11/20/2007
SQL 2008 FILESTREAM - 08/04/2007
CTE Concatenation - 01/01/2007