How To Use OAuth in My iPhone App? - iphone

I'm trying to configure OAuth into my iPhone app to connect to another web service but I'm having problems with it.
I have downloaded the google gtm-oauth files and added them to my project.
- (GTMOAuthAuthentication *)myCustomAuth {
NSString *myConsumerKey = #"2342343242"; // pre-registered with service
NSString *myConsumerSecret = #"324234234242"; // pre-assigned by service
GTMOAuthAuthentication *auth;
auth = [[[GTMOAuthAuthentication alloc] initWithSignatureMethod:kGTMOAuthSignatureMethodHMAC_SHA1
consumerKey:myConsumerKey
privateKey:myConsumerSecret] autorelease];
// setting the service name lets us inspect the auth object later to know
// what service it is for
auth.serviceProvider = #"RunKeeper";
return auth;
}
- (void)signInToCustomService {
NSURL *requestURL = [NSURL URLWithString:#"https://runkeeper.com/apps/token"];
NSURL *accessURL = [NSURL URLWithString:#"https://runkeeper.com/apps/token"];
NSURL *authorizeURL = [NSURL URLWithString:#"https://runkeeper.com/apps/authorize"];
NSString *scope = #"http://example.com/scope";
GTMOAuthAuthentication *auth = [self myCustomAuth];
// set the callback URL to which the site should redirect, and for which
// the OAuth controller should look to determine when sign-in has
// finished or been canceled
//
// This URL does not need to be for an actual web page
[auth setCallback:#"http://www.example.com/OAuthCallback"];
// Display the autentication view
GTMOAuthViewControllerTouch *viewController;
viewController = [[[GTMOAuthViewControllerTouch alloc] initWithScope:scope
language:nil
requestTokenURL:requestURL
authorizeTokenURL:authorizeURL
accessTokenURL:accessURL
authentication:auth
appServiceName:#"RunKeeper"
delegate:self
finishedSelector:#selector(viewController:finishedWithAuth:error:)] autorelease];
[[self navigationController] pushViewController:viewController
animated:YES];
}
This is the API I am trying to connect with: http://developer.runkeeper.com/healthgraph/registration-authorization

First, read up on oauth. it's a bit different from your normal login/pw type auth.
Second, you can use Google's oauth library at http://code.google.com/p/gtm-oauth/

Related

iOS Twitter User-Timeline fetching with v1.1 API

Recently Twitter has changed API to v1.1. With this API, it is now required to first login on Twitter and only then we can fetch timeline. Is that true?
Can we fetch user timeline without user login?
Thanks
I tried FHSTwitterEngine but I found STTwitter better:
https://github.com/nst/STTwitter
look at FHSTwitterEngine you can use newly FHSTwitterEngine and if you request this method without autenticating, the users status is removed... you have to send consumer key and token along with screen_name..
In FHSTwitterEngine
//get username pass to method. In Dictionary you can get all info
NSString *username = [[FHSTwitterEngine sharedEngine]loggedInUsername];
NSDictionary *data=[[FHSTwitterEngine sharedEngine]getUserProfile:username];
// method to get all user info
-(id)getUserProfile:(NSString *)username
{
if (username.length == 0) {
return getBadRequestError();
}
NSURL *baseURL = [NSURL URLWithString:url_users_show];
OAMutableURLRequest *request = [OAMutableURLRequest requestWithURL:baseURL consumer:self.consumer token:self.accessToken];
OARequestParameter *usernameP = [OARequestParameter requestParameterWithName:#"screen_name" value:username];
NSArray *params = [NSArray arrayWithObjects:usernameP, nil];
id userShowReturn = [self sendGETRequest:request withParameters:params];
return userShowReturn;
}
You can perfectly fetch a user timeline even if the user is not logged in.
You have to use the new "App Only" mode in which only the application is authentified.
See more details in this answer.

GTM OAuth2 retrieving access_token via Keychain not successful

I'm following Google's examples on how to authorize an app to access one or more APIs.
The problem is that when i authorise successfully i get the access_token, but after this i can't get it from the keychain it is stored into. I read somewhere that iPhone Simulator doesn't work with Keychain, is it because of that, and if it is can you tell me some other way to store my access token?
Here is my code:
static NSString *const kKeychainItemName = #"OAuthGoogleReader";
GTMOAuth2Authentication *auth;
auth = [GTMOAuth2ViewControllerTouch authForGoogleFromKeychainForName:kKeychainItemName
clientID:kClientID
clientSecret:kClientSecret];
BOOL isSignedIn = [auth canAuthorize];
if (isSignedIn) {
NSLog(#"Signed");
self.window.rootViewController = self.viewController;
auth.accessToken = [[NSUserDefaults standardUserDefaults] objectForKey:#"accessToken"];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:#"http://www.google.com/reader/api/0/subscription/list?access_token=%#", [auth accessToken]]]];
GTMHTTPFetcher* myFetcher = [GTMHTTPFetcher fetcherWithRequest:request];
// optional upload body data
//[myFetcher setPostData:[postString dataUsingEncoding:NSUTF8StringEncoding]];
[myFetcher setAuthorizer:auth];
[myFetcher beginFetchWithDelegate:self
didFinishSelector:#selector(myFetcher:finishedWithData:error:)];
// - (void)myFetcher:(GTMHTTPFetcher *)fetcher finishedWithData:(NSData *)retrievedData error:(NSError *)error;
}else{
NSString *scope = #"https://www.google.com/reader/api/";
GTMOAuth2ViewControllerTouch *viewController;
viewController = [[GTMOAuth2ViewControllerTouch alloc] initWithScope:scope
clientID:kClientID
clientSecret:kClientSecret
keychainItemName:kKeychainItemName
delegate:self
finishedSelector:#selector(viewController:finishedWithAuth:error:)];
self.window.rootViewController = viewController;
}
I get error:
2012-08-22 16:54:47.253 greader[20833:c07] Signed
2012-08-22 16:54:47.705 greader[20833:c07] Cannot authorize request with scheme http (<NSMutableURLRequest http://www.google.com/reader/api/0/subscription/list?access_token=(null)>)
as you can see access_token is just nil.
Also some simple examples on how to use this library would be great.
Thank you!
The gtm-oauth2 library handles storing and retrieving the access token and other auth values on the keychain. The app should not need to use the access token string directly, nor should the app put the authorization tokens into NSUserDefaults, as that is insufficiently secure.
gtm-auth2 also by default will refuse to attach an access token to a URL with an http: scheme. OAuth 2 is secure only when used with https: scheme URLs.

How can i implement GTMOAuth in iOS

i need to implement GTMOAuth to my iOS app..for this i have downloaded the OAuth Library and write some code
- (GTMOAuthAuthentication *)myCustomAuth {
NSString *myConsumerKey = #"f964039f2d7bc82054"; // pre-registered with service
NSString *myConsumerSecret = #"c9a749c0f1e30c9246a3be7b2586434f"; // pre-assigned by service
GTMOAuthAuthentication *auth;
auth = [[[GTMOAuthAuthentication alloc] initWithSignatureMethod:kGTMOAuthSignatureMethodHMAC_SHA1
consumerKey:myConsumerKey
privateKey:myConsumerSecret] autorelease];
// setting the service name lets us inspect the auth object later to know
// what service it is for
auth.serviceProvider = #"Custom Auth Service";
return auth;
}
- (void)signInToCustomService {
NSURL *requestURL = [NSURL URLWithString:#"http://alpha.easyreceipts.com/api/v1/oauth/request_token"];
NSURL *accessURL = [NSURL URLWithString:#"http://alpha.easyreceipts.com/api/v1/oauth/access_token"];
NSURL *authorizeURL = [NSURL URLWithString:#"http://alpha.easyreceipts.com/api/v1/oauth/authorize"];
NSString *scope = #"http://alpha.easyreceipts.com/api/v1/";
GTMOAuthAuthentication *auth = [self myCustomAuth];
// set the callback URL to which the site should redirect, and for which
// the OAuth controller should look to determine when sign-in has
// finished or been canceled
//
// This URL does not need to be for an actual web page
[auth setCallback:#"http://alpha.easyreceipts.com/api/v1/"];
// Display the autentication view
GTMOAuthViewControllerTouch *viewController;
viewController = [[[GTMOAuthViewControllerTouch alloc] initWithScope:scope
language:nil
requestTokenURL:requestURL
authorizeTokenURL:authorizeURL
accessTokenURL:accessURL
authentication:auth
appServiceName:#"My App: Custom Service"
delegate:self
finishedSelector:#selector(viewController:finishedWithAuth:error:)] autorelease];
viewController = [self.storyboard instantiateViewControllerWithIdentifier:#"myID"];
[[self navigationController] pushViewController:viewController
animated:YES];
}
but further i don't know how to implement it.Please help me Thanks in advance
First, if you want to implement an OAuth authentication system with the GTM library, you should get this one.
You can find the complete sources of GTMOAuth here.
Secondly, you can find an example of how to use it in the git repository too. You should find everything you need to at least authenticate.
If you have any more problem, please provide more informations.

Invalid Facebook access token

I am developing an application which posts videos to Facebook.
I have registered this app on Facebook, received APIkey, APIsecret, the app successfully passes authentication and receives the access token. Here is my code for authentication:
m_Facebook = [[Facebook alloc] init];
[m_Facebook logout:self];
m_FacebookUploader = [[FBVideoUpload alloc]init];
NSArray *permissions = [NSArray arrayWithObjects:#"publish_stream", #"offline_access",#"read_stream",nil];
m_Facebook.forceOldStyleAuth = YES;
[m_Facebook authorize:kApiKey permissions:permissions delegate:self];
However when trying to upload a video, the class FBVideoUpload tries to separate the access token into several parts:
- (NSString*) sessionID
{
NSArray *components = [accessToken componentsSeparatedByString:#"|"];
NSLog(#"components: %#", components);
return [components count] < 2 ? nil : [components objectAtIndex:1];
}
According to http://developers.facebook.com/docs/authentication/ the access token should contain several componenets, separated by "|", but the one I receive at authentication does not contain several components separated by a "|". The access_token I receive looks as follows:
AAA*GXJapke*BAGRlZC7aBLhiZB*MUEV*AAF6*ZBhZBw*0ER1M*vkXlRUZCwO*czfgs*wHbnA*BcTU*VrPZC*Yw3p*JmCIMZ*xSnCP*GqPRWZALgZDZ*
(I replaced some symbols with "*")
Here is my code for uploading the video:
[m_FacebookUploader setApiKey:kApiKey];
[m_FacebookUploader setAccessToken:m_Facebook.accessToken];
[m_FacebookUploader setAppSecret:kApiSecret];
[m_FacebookUploader startUploadWithURL:url params:params delegate:self];
I receive an error here:
if ([self sessionID] == nil) {
NSLog(#"Unable to retrieve session key from the access token.");
return;
}
Which not surprising since sessionID really returns nil.
Whatever library you're using to do that video upload is using some outdated logic to handle uploads. That whole method where it breaks apart the session key doesn't need to exist. Just use the access token you get back from FB with your video upload request. Also, be sure you're using our latest SDK https://github.com/facebook/facebook-ios-sdk

Twitter + oAuth nightmare

I'm trying to implement a custom login view to Twitter (I don't want that UIWebView).
I've downloaded many classes, and I'm so far having a nightmare with this. Now I'm trying to make Twitter + oAuth work. Here's the demo code (that works):
_engine = [[SA_OAuthTwitterEngine alloc] initOAuthWithDelegate: self];
_engine.consumerKey = kOAuthConsumerKey;
_engine.consumerSecret = kOAuthConsumerSecret;
[_engine requestRequestToken];
UIViewController *controller = [SA_OAuthTwitterController controllerToEnterCredentialsWithTwitterEngine: _engine delegate: self];
if (controller)
[self presentModalViewController: controller animated: YES];
else
[_engine sendUpdate: [NSString stringWithFormat: #"Already Updated. %#", [NSDate date]]];
Now what I wanna do is replace that SA_OAuthTwitterController with custom UITextFields. So I'm trying this:
_engine = [[SA_OAuthTwitterEngine alloc] initOAuthWithDelegate: self];
_engine.consumerKey = kOAuthConsumerKey;
_engine.consumerSecret = kOAuthConsumerSecret;
[_engine requestRequestToken];
[_engine requestAccessToken];
[_engine setUsername:#"username" password:#"password"];
[_engine sendUpdate:#"tweet"];
But I keep getting error 401. I'm probably missing a step. Anyone?
The view controller you are eliminating loads a webview that prompts the user to authenticate your application with twitter. If you don't ever have the user authenticate, you won't be able to make authenticated twitter calls. There is a way to do what you are wanting, however, you have to go through all of the OAuth steps yourself. Here are the steps as specified from a different web service (Vimeo), but the same rules apply:
Your application sends a request
with your consumer key, and signed
with your consumer secret, for a
something called a request token. If
we verify your application
correctly, we'll send you back a
request token and a token secret.
You'll then create a link for the user to click on with the request token.
When the user gets to Vimeo, they'll be prompted to allow your
application access to their account.
If they click yes, we'll send them
back to your application, along with
a verifier.
You'll then use the request token, verifier, and token secret to make
another call to us to get an access
token. The access token is what
you'll use to access the user's
information on Vimeo.
OAuth is a real pain in the rump, so good luck. ;-)
I think the bit you're missing is here, SA_OAuthTwitterEngine.m:103:
//This generates a URL request that can be passed to a UIWebView. It will open a page in which the user must enter their Twitter creds to validate
- (NSURLRequest *) authorizeURLRequest {
if (!_requestToken.key && _requestToken.secret) return nil; // we need a valid request token to generate the URL
OAMutableURLRequest *request = [[[OAMutableURLRequest alloc] initWithURL: self.authorizeURL consumer: nil token: _requestToken realm: nil signatureProvider: nil] autorelease];
[request setParameters: [NSArray arrayWithObject: [[[OARequestParameter alloc] initWithName: #"oauth_token" value: _requestToken.key] autorelease]]];
return request;
}
You will have to "fake" this user login out yourself, I believe by sending twitter the login credentials as a separate request. It appears that the setUsername method you're calling is actually called as a post operation once a valid access token has been received. See SA_OAuthTwitterEngine.m:185
//
// access token callback
// when twitter sends us an access token this callback will fire
// we store it in our ivar as well as writing it to the keychain
//
- (void) setAccessToken: (OAServiceTicket *) ticket withData: (NSData *) data {
if (!ticket.didSucceed || !data) return;
NSString *dataString = [[[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding] autorelease];
if (!dataString) return;
if (self.pin.length && [dataString rangeOfString: #"oauth_verifier"].location == NSNotFound) dataString = [dataString stringByAppendingFormat: #"&oauth_verifier=%#", self.pin];
NSString *username = [self extractUsernameFromHTTPBody:dataString];
if (username.length > 0) {
[[self class] setUsername: username password: nil];
if ([_delegate respondsToSelector: #selector(storeCachedTwitterOAuthData:forUsername:)]) [(id) _delegate storeCachedTwitterOAuthData: dataString forUsername: username];
}
[_accessToken release];
_accessToken = [[OAToken alloc] initWithHTTPResponseBody:dataString];
}
So the steps are as follows:
Request request token
Fake user login to twitter and get the pin value
Set the pin on the engine
Request access token
You can see where SA_OAuthTwitterController parses the pin out of the webview content in SA_OAuthTwitterController.m:156
#pragma mark Webview Delegate stuff
- (void) webViewDidFinishLoad: (UIWebView *) webView {
NSError *error;
NSString *path = [[NSBundle mainBundle] pathForResource: #"jQueryInject" ofType: #"txt"];
NSString *dataSource = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:&error];
if (dataSource == nil) {
NSLog(#"An error occured while processing the jQueryInject file");
}
[_webView stringByEvaluatingJavaScriptFromString:dataSource]; //This line injects the jQuery to make it look better
NSString *authPin = [[_webView stringByEvaluatingJavaScriptFromString: #"document.getElementById('oauth_pin').innerHTML"] stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceAndNewlineCharacterSet]];
if (authPin.length == 0) authPin = [[_webView stringByEvaluatingJavaScriptFromString: #"document.getElementById('oauth_pin').getElementsByTagName('a')[0].innerHTML"] stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceAndNewlineCharacterSet]];
[_activityIndicator stopAnimating];
if (authPin.length) {
[self gotPin: authPin];
}
if ([_webView isLoading] || authPin.length) {
[_webView setHidden:YES];
} else {
[_webView setHidden:NO];
}
}
hope this helps.
You have to use xAuth for custom user/pass controls. But it requires the permission from Twitter.