Runtime Error

37 views
Skip to first unread message

tmti_rob

unread,
Mar 20, 2012, 8:26:38 AM3/20/12
to FatSecret Platform API
Hi,

I'm trying to add the FatSecret API to an iPhone app I'm working on.
I've constructed the code that creates the API request following the
authentication instructions, and it returns an HTML Runtime Error:

"An application error occurred on the server. The current custom
error settings for this application prevent the details of the
application error from being viewed remotely (for security reasons).
It could, however, be viewed by browsers running on the local server
machine."

How can I find out what I'm doing wrong?

Many thanks,
Rob

tmti_rob

unread,
Mar 21, 2012, 8:16:58 AM3/21/12
to FatSecret Platform API
OK, I've got a little further, and now I'm getting the error:

<code>8</code>
<message>Invalid signature: oauth_signature
'kD86RV3czf0480AYds2YWDAPZyE='</message>

Here's my code:

NSString *nonce = [self nonce];
NSString *timestamp = [self timeStamp];

NSMutableArray *noramlizedParameters = [[NSMutableArray alloc]
init];

NSString *search_expression = @"search_expression=Rice Krispies";
[noramlizedParameters addObject:search_expression];

NSString *method = @"method=foods.search";
[noramlizedParameters addObject:method];

NSString *oauth_consumer_key = [NSString
stringWithFormat:@"oauth_consumer_key=%@", kConsumerKey];
[noramlizedParameters addObject:oauth_consumer_key];

NSString *oauth_nonce = [NSString stringWithFormat:@"oauth_nonce=
%@", nonce];
[noramlizedParameters addObject:oauth_nonce];

NSString *oauth_signature_method = @"oauth_signature_method=HMAC-
SHA1";
[noramlizedParameters addObject:oauth_signature_method];

NSString *oauth_timestamp = [NSString
stringWithFormat:@"oauth_timestamp=%@", timestamp];
[noramlizedParameters addObject:oauth_timestamp];

NSString *oauth_version = @"oauth_version=1.0";
[noramlizedParameters addObject:oauth_version];

NSArray *sortedArray;
sortedArray = [noramlizedParameters
sortedArrayUsingSelector:@selector(compare:)];
[noramlizedParameters removeAllObjects];
noramlizedParameters = [NSMutableArray
arrayWithArray:sortedArray];

NSString *percentEscapedString = (__bridge NSString
*)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,
(__bridge CFStringRef)[noramlizedParameters
componentsJoinedByString:@"&"], NULL, CFSTR(":/?#[]@!$&’()*+,;="),
kCFStringEncodingUTF8);

NSString *percentEscapedURL = (__bridge NSString
*)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,
(__bridge CFStringRef)@"http://platform.fatsecret.com/rest/
server.api", NULL, CFSTR(":/?#[]@!$&’()*+,;="),
kCFStringEncodingUTF8);

NSString *signatureBaseString = [NSString stringWithFormat:@"POST&
%@&%@",percentEscapedURL , percentEscapedString];

NSLog(@"signatureBaseString = %@\n\n", signatureBaseString);

NSDictionary *parametersDictionary = [NSDictionary
dictionaryWithObjectsAndKeys:
@"Rice Krispies",
@"search_expression",
@"foods.search", @"method",
kConsumerKey,
@"oauth_consumer_key",
nonce, @"oauth_nonce",
@"HMAC-SHA1",
@"oauth_signature_method",
timestamp,
@"oauth_timestamp",
@"1.0", @"oauth_version",
[self
signature:signatureBaseString], @"oauth_signature",
nil];

NSLog(@"parametersDictionary = %@\n\n", parametersDictionary);

[AppDelegate httpPOSTWithRelativePath:@"rest/server.api"
parameters:parametersDictionary block:^(NSData *returnedXMLData)
{
//[returnedXMLData writeToFile:[AppDelegate
dataFilePath:@"XMLData.xml"] atomically:TRUE];

NSString *XMLString = [[NSString alloc]
initWithData:returnedXMLData encoding:NSUTF8StringEncoding];
NSLog(@"xmlString = %@\n\n", XMLString);

TBXML *tbxml = [TBXML tbxmlWithXMLString:XMLString];

if (tbxml.rootXMLElement)
{
//[self traverseElement:tbxml.rootXMLElement];
}
}];

My base string looks like this:
POST&http%3A%2F%2Fplatform.fatsecret.com%2Frest%2Fserver.api&method
%3Dfoods.search%26oauth_consumer_key%XXXXXXXXXXXXXXXXXX%26oauth_nonce
%3DE16118C8-E0AE-4882-8B90-97928ECBDF2B%26oauth_signature_method
%3DHMAC-SHA1%26oauth_timestamp%3D1332331555%26oauth_version
%3D1.0%26search_expression%3DRice%20Krispies

As far as I can tell I've followed the signing instructions to the
letter, and I've checked my SHA1 hashing algorithm online and I get a
match. Can anyone help me get this working?

Many thanks,
Rob

John Freeman

unread,
Mar 21, 2012, 10:38:00 AM3/21/12
to fatsecret-p...@googlegroups.com, tmti_rob
On 3/21/12 7:16 AM, tmti_rob wrote:
> Here's my code:

Are you using the official Objective-C implementation of OAuth?

http://code.google.com/p/oauth/

> My base string looks like this:
>

> As far as I can tell I've followed the signing instructions to the
> letter, and I've checked my SHA1 hashing algorithm online and I get a
> match.

Did you check with this tool?

http://oauth.googlecode.com/svn/code/javascript/example/signature.html

Hope that helps,
John

tmti_rob

unread,
Mar 22, 2012, 5:53:40 AM3/22/12
to FatSecret Platform API
Thanks John,

That tool helped me figure out that my signature method was wrong. I
was using NSUTF8StringEncoding instead of NSASCIIStringEncoding, and I
wasn't adding an "&" character to the end of my Consumer Secret. I'm
now getting data back as expected.

For those other iPhone developers struggling with this, here are the
other bits of my code that generate the correct signature. These bits
of code were taken from GCOauth and used within my search view
controller. I didn't use GCOauth other than these three methods and it
all works perfectly. I modified the signature method to use
NSASCIIStringEncoding instead of the NSUTF8StringEncoding it was
using.

I used AFNetworking to send the request and TBXML to parse the
returned XML.

I will forge ahead with this project I'm working on, but if I get time
I may construct a small example project for other developers as I have
struggled with this for three days.

Thanks again for your help John.

- (NSString *)nonce
{
CFUUIDRef uuid = CFUUIDCreate(NULL);
CFStringRef string = CFUUIDCreateString(NULL, uuid);
CFRelease(uuid);
return (__bridge NSString *)string;
}

- (NSString *)timeStamp
{
time_t t;
time(&t);
mktime(gmtime(&t));
return [NSString stringWithFormat:@"%u", (t)];
}

- (NSString *)signature:(NSString *)signatureBaseString
{
// get signature components
NSData *base = [signatureBaseString
dataUsingEncoding:NSASCIIStringEncoding];
NSData *secret = [kConsumerSecret
dataUsingEncoding:NSASCIIStringEncoding];

// hmac
uint8_t digest[CC_SHA1_DIGEST_LENGTH];
CCHmacContext cx;
CCHmacInit(&cx, kCCHmacAlgSHA1, [secret bytes], [secret length]);
CCHmacUpdate(&cx, [base bytes], [base length]);
CCHmacFinal(&cx, digest);

// base 64
NSData *data = [NSData dataWithBytes:digest
length:CC_SHA1_DIGEST_LENGTH];
return [data base64EncodedString];
}

Don't forget to include these libraries and add an & to the end of the
secret.

#define kConsumerKey @"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
#define kConsumerSecret @"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&"

#import <CommonCrypto/CommonHMAC.h>
#import "NSData+Base64.h"
Reply all
Reply to author
Forward
0 new messages