My favorites | Sign in
Project Home Downloads Wiki Issues Source
Search
for
UsingOAuthConsumer  
A developer's guide to using OAuthConsumer in a Mac application.
Featured, Phase-Implementation
Updated Feb 4, 2010 by jon.r.cr...@gmail.com

Introduction

This guide is for developers interested in adding support for OAuth to their Mac apps. In order to use the framework, you must first get a copy from the svn repository and compile it. Compiling the framework will automatically run all of the unit tests.

Importing the Framework

There are 3 steps for adding the pre-compiled framework to your app in Xcode:

  1. Drag the framework into your Linked Frameworks group in Xcode, choosing to copy the framework instead of simply referencing it.
  2. Create a new Copy Files Build Phase for your app's main target.
  3. Drag the framework from the Linked Frameworks folder into the new Copy Files Build Phase and select "Frameworks" as its destination.

For now, please use this as a private embedded framework rather than copying it to the system's framework folder upon installation.

Using OAuthConsumer

Set Up

The first thing you will need in order to access a service providing OAuth support is a Consumer Key and a Consumer Secret. These must be obtained directly from the service provider. The OAuth Core 1.0 Spec does not address automatically generating such items.

The second thing required is a set of URLs provided for OAuth interactions by your service provider. These should be documented by the service provider and include:

  • Request Token URL
  • User Authorization URL
  • Access Token URL

Additionally, there should be a set of API standards to use in order to interact with the service after obtaining the OAuth credentials.

Once you have obtained your Consumer Key, Consumer Secret, and know your OAuth endpoint URLs, you are ready to begin writing code.

Getting an Unauthorized Request Token

The first order of business when communicating with an OAuth service provider is obtaining an Unauthorized Request Token. Using your Consumer Key, Consumer Secret, and the service provider's Request Token URL, you can send a request for an Unauthorized Request Token like this:

    OAConsumer *consumer = [[OAConsumer alloc] initWithKey:@"mykey"
                                                    secret:@"mysecret"];

    NSURL *url = [NSURL URLWithString:@"http://example.com/get_request_token"];

    OAMutableURLRequest *request = [[OAMutableURLRequest alloc] initWithURL:url
                                                                   consumer:consumer
                                                                      token:nil   // we don't have a Token yet
                                                                      realm:nil   // our service provider doesn't specify a realm
                                                          signatureProvider:nil]; // use the default method, HMAC-SHA1

    [request setHTTPMethod:@"POST"];

    OADataFetcher *fetcher = [[OADataFetcher alloc] init];

    [fetcher fetchDataWithRequest:request
                         delegate:self
                didFinishSelector:@selector(requestTokenTicket:didFinishWithData:)
                  didFailSelector:@selector(requestTokenTicket:didFailWithError:)];

Here is an example of a delegate method that uses a successful response to create the Request Token:

    - (void)requestTokenTicket:(OAServiceTicket *)ticket didFinishWithData:(NSData *)data {
        if (ticket.didSucceed) {
            NSString *responseBody = [[NSString alloc] initWithData:data
                                                           encoding:NSUTF8StringEncoding];
            requestToken = [[OAToken alloc] initWithHTTPResponseBody:responseBody];
        }
    }

Authorizing the Request Token

Now that you have an unauthorized request token, direct your user to the service provider's User Authorization URL so that they can approve access for your application:

    NSURL *url = [NSURL URLWithString:@"http://example.com/authorize"];
    [[NSWorkspace sharedWorkspace] openURL:url];

The service provider should first ensure the user is logged in, requiring authentication if this is not the case. The user will then have an opportunity to grant access for your application on the service provider's site. Service providers can use this interaction to limit access to certain kinds of assets if desired.

Obtaining an Access Token

Now that the Request Token has been authorized, an Access Token can be obtained in the same manner as described in "Getting an Unauthorized Request Token" with two exceptions:

  1. Instead of passing nil for the token parameter when creating the OAMutableURLRequest, pass the token obtained with the requestTokenTicket:didFinishWithData: method, above.
  2. The delegate methods might choose different names such as accessTokenTicket:didFinishWithData: and accessTokenTicket:didFailWithError:.

The delegate method can create the Access Token as an OAToken object in exactly the same manner as described above for the Request Token.

Using the Keychain

If you choose to store this token in the user's Keychain, it can be done like this:

    [accessToken storeInDefaultKeychainWithAppName:@"MyApp"
                               serviceProviderName:@"Example.com"];

Retrieving that same token from the Keychain on a different run of your app looks like this:

    OAToken *accessToken = [[OAToken alloc] initWithKeychainUsingAppName:@"MyApp"
                                                     serviceProviderName:@"Example.com"];

Accessing Protected Resources

At this point, you are ready to access the service provider's APIs, authenticating with OAuth in the background. You can either send requests using OAMutableURLRequest in the same manner as you would normally do with NSMutableURLRequest or you can continue to use the convenience objects OAServiceTicket and OADataFetcher. If you choose the former, be sure to call the prepare method on the request prior to initiating the connection or your request will not contain valid OAuth parameters.

Speaking of parameters, there are methods added to NSMutableURLRequest (and thus OAMutableURLRequest) to support setting parameters for requests. At the moment, there is a requirement to first set the HTTP method, then add or get the parameters as an NSArray.

Here is an example OAuth request for a protected resource using the GET method (default), HTTPS, the PLAINTEXT signature method, passing two parameters:

  1. title = My Page
  2. description = My Page Holds Text
    NSURL *url = [NSURL URLWithString:@"https://example.com/user/1/flights/"];
    OAMutableURLRequest *request = [[OAMutableURLRequest alloc] initWithURL:url
                                                                   consumer:consumer
                                                                      token:accessToken
                                                                      realm:nil
                                                          signatureProvider:[[OAPlaintextSignatureProvider alloc] init]];
    
    OARequestParameter *nameParam = [[OARequestParameter alloc] initWithName:@"title"
                                                                       value:@"My Page"];
    OARequestParameter *descParam = [[OARequestParameter alloc] initWithName:@"description"
                                                                       value:@"My Page Holds Text"];
    NSArray *params = [NSArray arrayWithObjects:nameParam, descParam, nil];
    [request setParameters:params];
    
    OADataFetcher *fetcher = [[OADataFetcher alloc] init];
    [fetcher fetchDataWithRequest:request
                         delegate:self
                didFinishSelector:@selector(apiTicket:didFinishWithData:)
                  didFailSelector:@selector(apiTicket:didFailWithError:)];
Comment by mar...@gmail.com, Nov 26, 2008

Marc M:: It's essential that you set the type of request (POST, GET, DELETE, ...) before setting any parameters. Otherwise they will sit in the wrong place.

Comment by kimptoc, Apr 24, 2009

Hi, thanks for the code. I am probably missing something (in oauth/web basics), but in a client app, what ties the user to the access token - I would have thought you'd need to pass in the username or similar in obtaining access token.

Or is the unauth req token passed in the "Authorizing the Request Token" step?

Thanks, Chris

Comment by dilee...@gmail.com, Jun 1, 2009

how to download the whole framework??

Comment by kimptoc, Jun 20, 2009

Stating the obvious, probably, but with the latest OAuth spec change, 1.0a, I guess the code needs an update to pass in the oauth_verifier which the host will give the consumer... (ie pincode from twitter).

http://oauth.googlecode.com/svn/spec/core/1.0a/drafts/3/oauth-core-1_0a.html#auth_step3

Thanks, Chris

Comment by kimptoc, Jun 21, 2009

Further to my comment yesterday, the changes I made to make this work with 1.0a was to add a verifier string to OAToken and then in the OAMutableURLRequest prepare method add it to the request, as follows:

@@ -141,7 +141,8 @@ signatureProvider:(id<OASignatureProviding, NSObject>)aProvider
     if ([token.key isEqualToString:@""])
         oauthToken = @""; // not used on Request Token transactions
     else
-        oauthToken = [NSString stringWithFormat:@"oauth_token=\"%@\", ", [token.key URLEncodedString]];
+        oauthToken = [NSString stringWithFormat:@"oauth_token=\"%@\", oauth_verifier=\"%@\", ", 
+                                         [token.key URLEncodedString], [token.verifier URLEncodedString]];
     

Regards, Chris

Comment by ord...@yourhead.com, Jun 25, 2009

Hi,

I borrowed heavily from Chris Kimpton's work and built a complete project out of it. Included all of the frameworks etc.

This means that you can click the download button. Open the project. Push run.

I did change one substantial thing. I subclass the MGTwitterEngine instead of modifying it. That way we don't have to fork MGTwitterEngine and can stay current with Matt's work and others' contributions.

My solution is to include an internal web-view into the project to display the "Accept" page. This basically replaces the "username/password" view that would normally be in a project.

I've opened all the source, and put it on github. Please feel free to use it, modify it, or comment on it. Thanks again to Chris and Matt for making this possible.

http://github.com/yourhead/OAuth_ObjC_Test_App/tree/master

Thanks, Isaiah YourHead? Software http://www.yourhead.com

Comment by mrjjwright@gmail.com, Jul 11, 2009

Hey Isaiah,

Thanks for the cool project bringing this together. I notice however that your code doesn't seem to take the user's pin that is displayed by Twitter after successful authentication, and I can't seem to authenticate with Twitter without it. Is there something I am missing? I get this error in the console after the pin is displayed (it goes away automatically):

2009-07-11 15:43:52.228 oauth_test_app[59733:10b] fail: 'Error Domain=NSURLErrorDomain Code=-1012 UserInfo?=0x10a9b20 "Operation could not be completed. (NSURLErrorDomain error -1012.)"'

Comment by fares.fa...@gmail.com, Jul 22, 2009

Hi,

As mrjjwright has mentioned, its a great sample you've bring Isaiah, but I also can't figure it out when Twitter replied successful registration and then respond with PIN and additional message "now simply back to application and enter the PIN". Where do this PIN need to be included, another URL post to Twitter or something else needs to be done first?

Cheers, Fares

Comment by pchukw...@gmail.com, Jul 24, 2009

When it comes to the Twitter PIN the user receives, I have my application expect the PIN the user gets after a successful request is made to get the request token.

so basically follow the steps of this wiki but do this right before the Obtaining an Access Token step:

Get the PIN number from the NSTextField that the user entered and set it to the 'verifier' property of the token...

[requestToken setValue:[twitterPIN stringValue] forKey:@"verifier"];
		url = [NSURL URLWithString:@"http://twitter.com/oauth/access_token"];

This is assuming that OAToken has a 'verifier' property (which I added). Then continue with the steps in this wiki.

Hope this helps.

Comment by akc1...@gmail.com, Jul 29, 2009

Is anyone else having trouble getting this to work after twitter's last update on July-27-2009? The update is supposed to prevent invalid signatures from being accepted.

Comment by pchukw...@gmail.com, Jul 29, 2009

yes I am having toruble. I keep getting "invalid/used nonce" error when trying to do a status update from Twitter, even though the nonce is indeed unique. Has anyone solved this issue?

Comment by pchukw...@gmail.com, Jul 29, 2009

If anyone else had the same issues I had, i was able to resolve them... i posted the issue, and fix on my blog. http://nullagenda.com/oauthconsumer-and-twitter-114

Comment by kimptoc, Jul 30, 2009

Same problem here, but fixed very quickly thanks to pchukwura, thanks for sharing the solution. For the impatient, just add an extra 'if' clause to only add the whole verifier clause if the verifier value is set, ie dont include the verifier= bit if no verifier...

Comment by zuks...@gmail.com, Aug 4, 2009

Where do we find this OAuthConsumer.Framework ? One in the repository wont compile. Help !!! any help regarding this issue will be highly appreciated.

Comment by pchukw...@gmail.com, Aug 4, 2009

What compile are you seeing?

Comment by zuks...@gmail.com, Aug 5, 2009

i resolved that issue ... now this one .... kindly reply soon, i cannot understand the cause of this error

dyld: Library not loaded: @executable_path/../Frameworks/OAuthConsumer.framework/Versions/A/OAuthConsumer

Referenced from: /Users/dssd/Desktop/MGTwitterEngine/MGTwitterEngine/build/Debug/MGTwitterEngine.app/Contents/MacOS/MGTwitterEngine Reason: image not found

---

Comment by mon.cas...@gmail.com, Aug 12, 2009

Hmm, looks like I didn't get some point:

1. I'm creating a OAMutableURLRequest 2. fulfill httpMethod amd headers 3. I can choose - use native SDK NSURLConnection or proposed OADataFetcher

I already have a valid access token and can't make queries with it through native SDK:

But I'm getting refuse from server (Couldn't authenticate you)

         NSString* strUrl = [[[NSString alloc] initWithFormat:@"%@%@", apiServer, requestUrl] autorelease];

	

	NSURL* url = [NSURL URLWithString:strUrl]; 

	

	OAMutableURLRequest *request = [[OAMutableURLRequest alloc] initWithURL: url

                                                                        consumer: consumer

                                                                        token: accessToken

                                                                        realm: nil

                                                                        signatureProvider: [[OAPlaintextSignatureProvider alloc] init]];

	

	[request setHTTPMethod: method];

	

	if(body != nil) {

		NSData* dataRequestBody = [body dataUsingEncoding:NSUTF8StringEncoding];

		[request setHTTPBody:dataRequestBody];

	}

	

	[request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];

	

	if( [method compare:@"PUT"] ==  NSOrderedSame ) {

		[request setValue:@"PUT" forHTTPHeaderField:@"X_HTTP_METHOD_OVERRIDE"];

	}

	

	[request prepare];

	

	NSHTTPURLResponse* resp = nil; 

	NSError* err = nil;

    

    NSData *serverData = [NSURLConnection sendSynchronousRequest: request   returningResponse: &resp  error: &err];

	SEL selector = (serverData != nil) ? success : fail;

	

	NSObject* param = (serverData != nil) ? (NSObject*) serverData : (NSObject*) err; 

	

	if(selector != nil) {

		if( object != nil) {

			[self performSelector: selector withObject: object  withObject: param ];

		} else {

			[self performSelector: selector withObject: param ];

		}

	}

this is app log:


2009-08-12 21:32:14.495 MyTool[4469:20b] String: PUT&http%3A%2F%2F10.1.1.1%2Fapi%2F0.9%2Fdataset%2Fcreate&%253Cdata%253E%253Cdataset%253E%253Cdata%2520k%3D%2522created_by%2522%2520v%26oauth_consumer_key%3DdwntFN9NJv9HrvMuqNgWbA%26oauth_nonce%3D067BD7D5-9C90-47EC-B19E-E8ACED9472E0%26oauth_signature_method%3DPLAINTEXT%26oauth_timestamp%3D1250101934%26oauth_token%3DubZlywqgHWaaoUlPqdDnvQ%26oauth_version%3D1.0, Array: %253Cosm%253E%253Cdataset%253E%253Cdata%2520k=%2522created_by%2522%2520v&oauth_consumer_key=dwntFN9NJv9HrvMuqNgWbA&oauth_nonce=067BD7D5-9C90-47EC-B19E-E8ACED9472E0&oauth_signature_method=PLAINTEXT&oauth_timestamp=1250101934&oauth_token=ubZlywqgHWaaoUlPqdDnvQ&oauth_version=1.0
2009-08-12 21:32:14.496 MyTool[4469:20b] Headers: {
    Authorization = "OAuth realm=\"\", oauth_consumer_key=\"dwntFN9NJv9HrvMuqNgWbA\", oauth_token=\"ubZlywqgHWaaoUlPqdDnvQ\", oauth_signature_method=\"PLAINTEXT\", oauth_signature=\"3iF9JIzYQPT5JkvrEXHujCLhI03An302P94JeQoF8%26minE6ZinCiaNlCFfbazOamC1DsD3FcvVF4C1fM5k\", oauth_timestamp=\"1250101934\", oauth_nonce=\"067BD7D5-9C90-47EC-B19E-E8ACED9472E0\", oauth_version=\"1.0\"";
    "Content-Type" = "application/x-www-form-urlencoded";
    "X_http_method_override" = PUT;
}
Comment by mon.cas...@gmail.com, Aug 13, 2009

GUYS THERE IS A BUG!

IF YOU USING REQUEST BODY ( setHTTPBody: body?; )

FIRST - SIGN THE REQUEST ( eg prepare?;) and then SET THE BODY

OR fix it in signatureBaseString for OAMutableURLRequest

Comment by hamfil...@gmail.com, Nov 15, 2009

Is there anyone who can add the verifier code (proposed by pchukwura and kimptoc) to the SVN repository? The framework seems kinda useless without this, no? Thank you!

Comment by hamfil...@gmail.com, Nov 15, 2009

I had some problems authorizing the request token. The OAuth provider complained I did not provide a request token with the example code in the wiki here:

    NSURL *url = [NSURL URLWithString:@"http://example.com/authorize"];
    [[NSWorkspace sharedWorkspace] openURL:url];

I added the request token to the URL sent to the OAuth provider like this:

    NSString *urlString = [NSString stringWithFormat:@"http://example.com/authorize?auth_token=%@", requestToken.key];
    NSURL *url = [NSURL URLWithString:urlString];
    [[NSWorkspace sharedWorkspace] openURL:url];

Probably not the best way to do it but hey, it works.

Comment by hamfil...@gmail.com, Nov 15, 2009

@zuksh.5 Did your set the destination for the "Copy Files" phase to "Frameworks"? I had a similar problem. Think you are just linking the framework in the wrong way. Remove it and try again step by step.

Comment by tom.digr...@gmail.com, Dec 1, 2009

Not sure if this is an issue or if I'm using an old version. Should 'ticket' be released toward the end of OADataFetcher.m so there isn't a memory leak? Or is that being released somewhere else?

Comment by macb...@gmail.com, Feb 9, 2010

Support PIN verification code: http://github.com/macbury/OAuthConsumer

Comment by jerrykri...@gmail.com, Mar 13, 2010

I want the Delicious client in my app to access Yahoo accounts using OAuth

What I did:

  • Built OAuthConsumer
  • Added it to my project
  • Pasted in the code given above in the section Getting an Unauthorized Request Token
  • Changed @"mySecret" and @"myKey" to a secret and key I obtained for my app from Yahoo.
  • Changed request url to https://api.login.yahoo.com/oauth/v2/get_request_token.
  • Build and run.

Result: NSURLError -1012 "Operation cannot be completed".

Analysis: OAuthConsumer uses +sendSynchronousRequest:returningResponse:error:? which, unfortunately, always seems to return a -1012 error instead of returning the error received from the server. (That's the main reason why I always use the synchronous methods instead.)

So, I added some more logs and found that OAuthConsumer is sending an HTTP POST, a null body, and one key/value pair in the Request Headers. The key is "Authorization" and the value is a comma-separated string of sub-keys and values. The sub-keys are: OAuth realm, oauth_consumer_key, oauth_signature_method, oauth_signature, oauth_timestamp, oauth_nonce, and oauth_version.

Then I went searching for some more ideas and found Joe Chung's php project:

http://nullinfo.wordpress.com/oauth-yahoo/

I set it up similarly, ran it, and immediately got a 200 response and request token from Yahoo!

So, why does Joe Chung's code work with Yahoo! and OAuthConsumer does not?

Well, the request sent by Joe Chung's code is different. It's also a POST, and pretty much the same key-value pairs, but instead of concatenating all of them all into one big key, they are separate key-value pairs in the header. Like a normal request, I would say!

Can anyone explain why OAuthConsumer concatenates the key-value pairs into one big pair? It doesn't seem to work for me.

Comment by jerrykri...@gmail.com, Mar 13, 2010

Well, now I'm even more confused. I looked at the OAuth standard document, and it appears that the way Jon has done it in OAuthConsumer, wrapping all the key-value pairs into one big "Authorization" key, may be correct. (I haven't an hour studying the stupid thing in detail yet.) However, it sure does not work with Yahoo!

Meanwhile, I wrote my own Objective-C code, passing the 6+signature = 7 parameters in the normal way, strung together with ampersands in the http body, and it works. Well, at least I got my request authorization URL, and Yahoo! recognizes it as wanting to link to my app. Oh, well. On to the authorization token.

Comment by jerrykri...@gmail.com, Mar 15, 2010

After getting my token and reading the OAuth standard a little more, now I have a theory as to why I was so confused. Leaving out the gory details, it seems that there are two kind-of request types in OAuth. The first type, used to get your tokens, requires a normal request; the 6 (more or less) values are each sent as a key-value pair. The second mode, used to access API after you've got your token, adds the OAuth realm to the parms and then wraps all of them into that comma-separated "Authorization" key-value pair. So, apparently I was using the "second type" method in OpenAuthConsumer? when I should have been using the "first type".

Lesson: OAuth is so complicated that you can't just drop OAuthConsumer into a project. Probably you should study the OAuth standard first.

Comment by nathanie...@gmail.com, Apr 5, 2010

In order to add a callback to the OAuth call it must now be added to the http://twitter.com/oauth/request_token request.

OAMutableURLRequest *request = [[OAMutableURLRequest alloc] initWithURL:url
                                                                   consumer:consumer
                                                                      token:nil   // we don't have a Token yet
                                                                      realm:nil   // our service provider doesn't specify a realm
                                                          signatureProvider:nil]; // use the default method, HMAC-SHA1
		
	[request setOAuthParameterName:@"oauth_callback" withValue:@"callbackurl:"];
	
    [request setHTTPMethod:@"POST"];

This also requires a small addition to the file OAMutableURLRequest.m. Find the signatureBaseString method and add the following (new code is between the Begin Custom and End Custom tags).

for (OARequestParameter *param in [self parameters]) {
        [parameterPairs addObject:[param URLEncodedNameValuePair]];
    }
	
	// Begin Custom
	for (NSString *parameterName in [[extraOAuthParameters allKeys] sortedArrayUsingSelector:@selector(compare:)]) { 
		[parameterPairs addObject:[[OARequestParameter requestParameterWithName:parameterName value:[extraOAuthParameters objectForKey:parameterName]] URLEncodedNameValuePair]]; 
	} 
    // End Custom
	
    NSArray *sortedPairs = [parameterPairs sortedArrayUsingSelector:@selector(compare:)];
    NSString *normalizedRequestParameters = [sortedPairs componentsJoinedByString:@"&"];

credit where credits due for that last bit. http://crizin.net/category/%EC%BB%B4%ED%93%A8%ED%84%B0%20%EC%96%98%EA%B8%B0

And finally, for anyone using the Twitter api callback with a custom url scheme. Just got this info from their api support...

You can either append a path component to the custom callback or remove the slashes, e.g.: 'myapp://oauth' or 'myapp:'

Comment by luff...@gmail.com, May 18, 2010

Hello,

I work on an iphone projet with twitter and your framework,

In order to have an Authorizing the Request Token on an iPhone project, i cannot use this request:

NSURL url = URLWithString:@"http://example.com/authorize"?; [sharedWorkspace? openURL:url];

temporally, I use an UIwebView to display the Twitter User Authorization, and I watch on the Url of the WebView? to analyse if the user is logged.

But with your framework there is a method to do the same thing without analyse the url (like callbacks or something like this) ??

Comment by msan...@student.chalmers.se, May 20, 2010

Hello, I am trying to submit some JSON data to a web service using a POST request. For some reason however, the framework seems to look for additional parameters in the HTTP body where I put my JSON data. This results in an index-out-of-range exception since it is unable to split the HTTP body into parameter components.

How would I go about making a POST request together with some data that I want to send to the receiver without running into this exception?

Comment by kickingv...@gmail.com, Jun 4, 2010

Spent the past week with OAuthConsumer getting it to work with the iPhone and thought I'd share. I've got an example iPhone app that demonstrates Twitter OAuth integration using UIWebView for authorization. http://code.google.com/p/oauthconsumer-iphone/

Thanks Jon + all others involved for OAuthConsumer.

Comment by RyMoul...@gmail.com, Jun 10, 2010

Hi I'm trying to use this to post to twitpic, and am unable to set the http body, I keep getting an NSRangeException. Anyone have any idea how to send image data with OAMutableRequest?

Comment by bryanmeu...@gmail.com, Jun 20, 2010

When i try to get my accestoken from Twitter i get the following console output:

Error Domain=NSURLErrorDomain Code=-1012 UserInfo?=0x200323fe0 "The operation couldn’t be completed. (NSURLErrorDomain error -1012.)" Underlying Error=(Error Domain=kCFErrorDomainCFNetwork Code=-1012 UserInfo?=0x200324020 "The operation couldn’t be completed. (kCFErrorDomainCFNetwork error -1012.)")

What am I doing wrong? I think it has something to do with the adding of the verifier property in the framework. If someone could explain me that i can check if i did it the right way. thanks!

Comment by mariani...@gmail.com, Jun 25, 2010

I'm getting "duplicate symbol" in OARequestParameter when building for 4.0 SDK. I get a clean build for Simulator, but errors when building for Device.

My problem is similar to that experienced for Three20 in similar circumstances, discussed and fixed in this blog post. http://groups.google.com/group/three20/browse_thread/thread/60630131d9961416

Any ideas on how to fix this?

Comment by bryanmeu...@gmail.com, Jun 26, 2010

That NSURLErrorDomain was kind-off self-explaining.. The URL i used was incorrect so the data didn't get sent at all, which the error told me. LOL I forgot one letter in the URL. But ok, I found it, it works now!

On to: Tweeting itself.

Comment by bryanmeu...@gmail.com, Jun 27, 2010

Ok for everyone that needs the verifier in the framework, open up the source code of the framework and open up your OAToken.h.

Every Bold code i type is an addition or a change, bear that in mind.

@interface OAToken : NSObject { @protected

NSString key; NSString secret;
  • SString verifier;
} @property(retain) NSString key; @property(retain) NSString secret; @property(retain) NSString verifier;

then open up your OAToken.m and change the following

@implementation OAToken

@synthesize key, secret, verifier;

#pragma mark init

- (id)init {

if (self = init?) {
self.key = @""; self.secret = @"";
  • elf.verifier = @"";
}
return self;
}

- (id)initWithKey:(NSString )aKey secret:(NSString )aSecret {

if (self = init?) {
self.key = aKey; self.secret = aSecret;
  • elf.verifier = @"";
} return self;
}

When that's done find the initWithHTTPResponseBody in your OAToken.m and change this

- (id)initWithHTTPResponseBody:(NSString )body {

if (self = init?) {
NSArray pairs = componentsSeparatedByString:@"&"?;
for (NSString pair in pairs) {
NSArray elements = componentsSeparatedByString:@"="?; if ([objectAtIndex:0? isEqualToString:@"oauth_token"]) {
self.key = [objectAtIndex:1? stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
} else if ([objectAtIndex:0? isEqualToString:@"oauth_token_secret"]) {
self.secret = [objectAtIndex:1? stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
} else if ([objectAtIndex:0? isEqualToString:@"oauth_verifier"]) {
self.verifier = [objectAtIndex:1? stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
}
}
}

then open up the OAMutableRequest.m and edit the following:

- (void)prepare {

// sign
// Secrets must be urlencoded before concatenated with '&' // TODO: if later RSA-SHA1 support is added then a little code redesign is needed
signature = signClearText:[self _signatureBaseString?
withSecret:[NSString stringWithFormat:@"%@&%@",
[consumer.secret URLEncodedString],
[token.secret URLEncodedString]]];
// set OAuth headers NSString oauthToken; if ([token.key isEqualToString:@""]) {
oauthToken = @""; // not used on Request Token transactions
} else {
oauthToken = [NSString stringWithFormat:@"oauth_token=\"%@\", oauth_verifier=\"%@\", ",
[token.key URLEncodedString], [token.verifier URLEncodedString]];
} NSMutableString extraParameters = string?;
// Adding the optional parameters in sorted order isn't required by the OAuth spec, but it makes it possible to hard-code expected values in the unit tests. for(NSString parameterName in [allKeys? sortedArrayUsingSelector:@selector(compare:)]) {
[extraParameters appendFormat:@", %@=\"%@\"",
URLEncodedString?, [objectForKey:parameterName? URLEncodedString]];
}
NSString oauthHeader = [NSString stringWithFormat:@"OAuth realm=\"%@\", oauth_consumer_key=\"%@\", %@oauth_signature_method=\"%@\", oauth_signature=\"%@\", oauth_timestamp=\"%@\", oauth_nonce=\"%@\", oauth_version=\"1.0\"%@",
URLEncodedString?, [consumer.key URLEncodedString], oauthToken, [name? URLEncodedString], URLEncodedString?, timestamp, nonce,
extraParameters];
setValue:oauthHeader forHTTPHeaderField:@"Authorization"?;
}

return self;

}

Now whenever you send the unauthorized token + the verifier (e.g. twitter pin) to the access token url, you will get authorized ;)

Good luck all :)

Comment by massimil...@gmail.com, Aug 31, 2010

hi there this is my problem: when i try to put update status on linked In i've the next error message <error>

<status>401</status> <timestamp>1283259846143</timestamp> <error-code>0</error-code> <message>unauthorized?. OAU:kIs76mnj8_rRg2O1zadJytBekKZpk62PLmOQL1tG_YaSonKhDen5CAMmTQDnO5Vd|031dc105-1a15-464f-a0e3-aa0d226829cd|01|01:1283259845:/VwFlbqHqzaakoIXdWUqQs83MbI=</message>
</error>

this is my code:

NSURL url = URLWithString:@"http://api.linkedin.com/v1/people/~/current-status"?;

OAMutableURLRequest request1 = [alloc? initWithURL:url
consumer:consumer
token:accToken// realm:nil //
signatureProvider: nil] ; //

NSLog(@"mytoken%@",token?);

setHTTPMethod:@"PUT"?;

setHTTPBodyWithString:@"<?xml version=''1.0'' encoding=''UTF-8' standalone=''yes''?><current-status>is setting their status using the LinkedIn API.</current-status>"?; prepare?;
OADataFetcher fetcher = [alloc? init]; [fetcher fetchDataWithRequest:request1
delegate:self
didFinishSelector:@selector(status:didFinishWithData:)
didFailSelector:@selector(status:didFailWithError:)];

any ideas?? Please help me!

Comment by ikevinjp...@gmail.com, Sep 12, 2010

I have checked out the code, and built a Release / OAuthConsumer into a OAuthConsumer.framework. I then added this framework using several methods, including the instructions given above. No matter which method I add the framework, I get this error:

---

"OBJC_CLASS$OAConsumer", referenced from:

objc-class-ref-to-OAConsumer in TestAppDelegate??.o

ld: symbol(s) not found

collect2: ld returned 1 exit status

---

... when I simply try to put this one line of code into my TestAppDelegate???.m file:

OAConsumer consumer = alloc? initWithKey:@"mykey" ecret:@"mysecret"];

What's wrong? It seems like the linker cannot find the symbol. Please help me! Thanks!

Comment by drechsel...@gmail.com, Oct 7, 2010

Hi... i tried to make a little Twitterapp for Mac and have a valid accesstoken... When requesting the home_timeline of the user, i´m getting the 1012 error...

The result from using the OAAsynchronousDataFetcher is "invalid signature". I know my accesstoken key and secret are the right ones (actually i´m testing with "my" accesstoken, provided by twitters "my apps" page)

Can anybody help me?

NSURL url = URLWithString:@"http://api.twitter.com/1/statuses/home_timeline.xml"?;
OAMutableURLRequest request = [alloc? initWithURL:url
consumer:consumer token:accessToken realm:nil
signatureProvider:nil];

setHTTPMethod:@"GET"?;
OADataFetcher fetcher = [alloc? init];
[fetcher fetchDataWithRequest:request
delegate:self
didFinishSelector:@selector(apiTimeline:didFinishWithData:)
didFailSelector:@selector(noneTimeline:didFailWithError:)];

Comment by cybercow...@gmail.com, Nov 9, 2010

I really thank kickingvegas to keep it simple - what's simple. I really appreciate the week he spent to make the iPhone version working. I'm asking myself, if is possible to hidesomehow the UIWebView and show custom login with custom controller and make the post. I really dislike the visual solution from twitter, it's plain basic looking on a mobile device. There is a solution to use xAuth, but is really needed ?

Comment by trinity6...@gmail.com, Dec 19, 2010

Will this work on the iPhone too? What do I need to do to make this work on the iPhone?

Comment by trinity6...@gmail.com, Dec 19, 2010

Wait a minute. How do I download it? I've been pressing on every link I could find and it's not working...

Or am I supposed to copy it all?

Comment by borl...@gmail.com, Dec 28, 2010

to trinity6310: Use this : svn checkout http://oauth.googlecode.com/svn/code/obj-c/OAuthConsumer/ oauth

Comment by griffith...@gmail.com, Feb 18, 2011

I think you can post application/json by the following code!!

NSURL url = URLWithString:@"https://example.com/user/1/flights/"?; OAConsumer consumer = [alloc? initWithKey:@"mykey" secret:@"mysecret"]; OAToken accessToken = [alloc? initWithKeychainUsingAppName:@"MyApp?" serviceProviderName:@"Example.com"];

OAMutableURLRequest req = [alloc? initWithURL:url consumer:consumer token:accessToken realm:nil signatureProvider:nil]; setHTTPMethod:@"POST"?; prepare?; setHTTPBody:[(NSString*)jsonStr dataUsingEncoding:NSUTF8StringEncoding?]; setValue:@"application/json" forHTTPHeaderField:@"Content-Type"?;

OADataFetcher fetcher = [alloc? init]; fetchDataWithRequest:request delegate:self didFinishSelector:@selector(apiTicket:didFinishWithData:) didFailSelector:@selector(apiTicket:didFailWithError:)?;

Comment by maximusd...@hotmail.com, Feb 21, 2011

Guys, how can I compile the Framework?

Comment by crai...@me.com, May 18, 2011

Thanks so much man, you really helped me so much.

Comment by berty...@gmail.com, May 30, 2011

Hi, does OAuthConsumer support OAuth 2.0 standard?

Comment by domi...@doo.net, Jul 14, 2011

does it/will it ;) would be great!

Comment by danieldu...@gmail.com, Aug 7, 2011

I want a complant form consomer one on me email to fill out and email caplaint to a company that I have complaint

Comment by k.shi...@ldh.01s.in, Aug 26, 2011

hello every one !! i am trying to integrate twitter in my native application . I submitted my application at https://dev.twitter.com/. I am using MGTwitterEngine (api) to post update on twitter wall. I have some sample application and get successfully logged in but as i am not xAuth authenticated user, twitter suggested me to set upone-time OAuth workflow to obtain the access token for a single account. Now my question is where i should provide access token and access token secret in MGTwitterEngine classes?

Comment by sathish...@gmail.com, Sep 21, 2011

Hi,

I am integrating OauthConsumer? in my iPhone app code and connecting to my server which already working with Oauth. But the problem what I am facing is, then oauth_nonce generated in my iPhone is different from oauth_nonce generated in my server by using same oauth_consumer_key and oauth_secrect_key. How could I resolve this problem. Can some one help me in this?

Thanks in Advance. Sathish

Comment by emailmej...@gmail.com, Oct 12, 2011

It must be something small but it's driving me nuts.

If I use HTTP method as POST, I am getting error -1012 saying "The operation couldn’t be completed. (NSURLErrorDomain error -1012.)" If I change the method to "GET" or "PUT" or "DELETE", this error doesn't come. For the operation I am trying, it needs to be "POST" only.

Anyone expert here or have come across and resolved this issue, request you to please help.

This is what I am up to...

  1. I am done with authorization part and have valid request token and secret
  2. Other GET apis are working fine and there is no any error.

This is where I am stuck (with HTTP POST)

1. I created OAMutableURLRequest (Note this same request and below flow works for "GET" call)

    request = [[[OAMutableURLRequest alloc] initWithURL:url
                                               consumer:consumer
                                                  token:self.accessToken
                                               callback:nil signatureProvider:nil]  autorelease];

2. Setting HTTP method as POST

    [request setHTTPMethod : @"POST"];

3. Preparing a request

    [request prepare];

4. Setting HTML body

    [request setHTTPBody : [@"<?xml version='1.0' encoding='UTF-8'?><my-xml-data>Something</my-xml-data>" dataUsingEncoding:NSUTF8StringEncoding]];

5. Making a synchronous call

    NSError *anError = nil;

    NSURLResponse* response;

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

    if (data == nil || anError != nil) {
        NSLog(@"Something went wrong: %@", anError);
    }

   //Now response is nil and there is always an error ""The operation couldn’t be completed. (NSURLErrorDomain error -1012.)" 

If I just change the method from POST to "GET", "PUT" then error goes away.

This is what I tried so far but none worked...

  1. Calling prepare? after/before setting HTTP method
  2. Calling prepare? after/before setting HTTP body
  3. Using OADataFetcher (asynchronous call) but it did not work too

I can confirm request has Authorization header, content length and request body (NSData). I am not sure what do I need to do. Please let me know if there is a fix for this or what am I doing wrong.

Thanks and Regards, Rajendra

Comment by emailmej...@gmail.com, Oct 12, 2011

WoW! Figured out what what going wrong finally. I was forgetting to set "Content-Type" header. Added below line and it works.

[request setValue:@"application/xml" forHTTPHeaderField:@"Content-Type"];}
}}

Looks like I answered my own query but thought to share back in case someone finds this helpful.
Comment by agrawalg...@gmail.com, Jan 7, 2012

Hi,

I'm facing such a problem with Twitter + Oauth MGT Engine. when i try to login and after login show Authenticate user (null). Pls help

Comment by rbb.suk...@gmail.com, Jan 27, 2012

Hi ,

i am trying to register my pod to diaspora. i have client public_key , secret_key and i want to generate token_key how can i do that .please explane in brief . when i hit the url with these keys its not going inside "if (ticket.didSucceed)" condition . does any buddy know where i am going wrong.

Comment by chris.dr...@gmail.com, Feb 14, 2012

Is there an update to this for OAuth 2.0? I've been looking everywhere for a good example but I'm not finding anything.

Comment by eiman...@vaiciunas.info, Feb 17, 2012

chris - I have replaced delegate calls with block support: https://github.com/walkingsmarts/oauthconsumer

Comment by cynt...@pinterest.com, Mar 4, 2012

For one USERNAME/PASSWORD pair, I can reliably crash our app with the following stack trace:

0 CoreFoundation 0x33abc8bf __exceptionPreprocess + 163 
1 libobjc.A.dylib 0x31ade1e5 objc_exception_throw + 33
2 CoreFoundation 0x33a14275 -[__NSArrayI objectAtIndex:] + 165
3 -[OAMutableURLRequest parameters] (OAMutableURLRequest.m:241)
4  -[OAMutableURLRequest _signatureBaseString] (OAMutableURLRequest.m:179)
5  -[OAMutableURLRequest prepare] (OAMutableURLRequest.m:133)

Has anyone seen this before?


Sign in to add a comment
Powered by Google Project Hosting