I'm currently building an iOS application and want to include Flattr-Support over the Flattr-API v2.
I've already created my application at https://flattr.com/apps/ and got the key and secret.
The problem is that I have to provide a callback-URL in the application-settings at flattr even if I select "client" as application type. In addition only http://... callback-URLs seem to be allowed in the input field so I can't set a callback URL to open my application (something like myApp://...)
How do I implement the Flattr oAuth process for client applications?
Are there any detailed instructions how to implement the flattr-authentication with a non-web-based / iOS application?
I planned to use the JDG OAuthConsumer library but this doesn't seem to work - any other iOS librarys I could use?
A short description of my implementation using the Flattr API v2 to flattr a thing from my iOS application:
I'm currently using the "Google Toolbox for Mac - OAuth 2 Controllers":
http://code.google.com/p/gtm-oauth2/
Create a Token to be authenticated:
- (GTMOAuth2Authentication *)flattrAuth {
NSURL *tokenURL = [NSURL URLWithString:#"https://flattr.com/oauth/token"];
// We'll make up an arbitrary redirectURI. The controller will watch for
// the server to redirect the web view to this URI, but this URI will not be
// loaded, so it need not be for any actual web page.
NSString *redirectURI = #"http://localhost/"; //for me localhost with / didn't work
GTMOAuth2Authentication *auth;
auth = [GTMOAuth2Authentication authenticationWithServiceProvider:#"MyApplication"
tokenURL:tokenURL
redirectURI:redirectURI
clientID:clientKey
clientSecret:clientSecret];
return auth;
}
Create a ViewController to authenticate the token:
- (GTMOAuth2ViewControllerTouch*)getSignInViewController{
GTMOAuth2Authentication *auth = [self flattrAuth];
// Specify the appropriate scope string, if any, according to the service's API documentation
auth.scope = #"flattr";
NSURL *authURL = [NSURL URLWithString:#"https://flattr.com/oauth/authorize"];
GTMOAuth2ViewControllerTouch *viewController;
viewController = [[[GTMOAuth2ViewControllerTouch alloc] initWithAuthentication:auth
authorizationURL:authURL
keychainItemName:keychainItemName
delegate:self
finishedSelector:#selector(viewController:finishedWithAuth:error:)] autorelease];
return viewController;
}
and the delegate method:
- (void)viewController:(GTMOAuth2ViewControllerTouch *)viewController
finishedWithAuth:(GTMOAuth2Authentication *)auth
error:(NSError *)error {
if (error != nil) {
DLog(#"Flattr sign-in failed with error: %#", [error localizedDescription]);
} else {
DLog(#"Flattr Signin success");
authToken = [auth retain];
}
}
You can display the Viewcontroller in your application - it displays the flattr-login to the user so he can authenticate the application.
You can flattr a thing with the authentication token this way:
NSString* flattrURL = #"https://api.flattr.com/rest/v2/things/%qi/flattr";
NSURL* u = [NSURL URLWithString:[NSString stringWithFormat:flattrURL, item.flattrThingID]];
NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:u];
[authToken authorizeRequest:request completionHandler:^(NSError *error){
if (error == nil) {
// the request has been authorized
NSURLConnection* connection = [[[NSURLConnection alloc] initWithRequest:request delegate:self] autorelease];
if(!connection){
//TODO: handle error
} else {
[connection start];
}
} else {
//TODO: handle error
}
}];
Now implement the NSURLConnectection delegate methods and parse the JSON responses.
The GTMOAuth2 library allows you to save the authenticated token to the keychain. Look at their introduction at http://code.google.com/p/gtm-oauth2/wiki/Introduction#Retrieving_Authorization_from_the_Keychain for instructions.
When you wan't to authenticate a desktop/mobile app you would wan't to use the oauth2 implicit grant flow. As you register your flattr application use a application specific URI that will callback to your application, ex. iphone-application://oauth-callback.
When you authenticate the application with us you use the response_type token instead of code. This will create a token at once and redirect you back to your application.
Ex. request URL: https://flattr.com/oauth/authorize?client_id=2134&redirect_uri=iphone-application://oauth-callback&response_type=token
If the resource owner will authorize your application we will send a HTTP 302 and redirect you back to your redirect uri.
Ex. response 302 Location: iphone-application://oauth-callback#access_token=e5oNJ4917WAaJaO4zvoVV2dt3GYClPzp&token_type=bearer
Currently we don't have any detailed documentation explaining how to do the implicit grant but we are working on the documentation. Meanwhile i'm all ears.
https://github.com/nxtbgthng/OAuth2Client is a iOS oauth2 library but I don't know if it's any good.
This one looks good: https://github.com/neonichu/FlattrKit
Related
I used the code from this sample. To get the number of user's unread messages (that's what I need), I need to send this GET request
https://www.googleapis.com/gmail/v1/users/me/labels/UNREAD?key={MY_API_KEY}
like in this example. But I guess that the {ACCESS_TOKEN} should be here instead of {MY_API_KEY}. If so, could anybody tell me how to get the access token using AFNetworking or auth from the sample?
As discussed in Authorizing Your App with Gmail
Gmail uses the OAuth 2.0 protocol for authenticating a Google account and authorizing access to user data. You can also use Google+ Sign-in to provide a "sign-in with Google" authentication method for your app.
If using AFNetworking is still your preference as requested, you may use the guide on how to get the access token given in this GitHub post - AFOAuth2Manager.
Solution given in this SO post - How to get the number of unread threads in INBOX with Gmail API might also help.
To get the access token to make an authorize request to the Google API you should implement the following methods:
- (GTMOAuth2ViewControllerTouch *)createAuthController {
GTMOAuth2ViewControllerTouch *authController;
// If modifying these scopes, delete your previously saved credentials by
// resetting the iOS simulator or uninstall the app.
NSArray *scopes = [NSArray arrayWithObjects:kGTLAuthScopeGmailReadonly, nil];
authController = [[GTMOAuth2ViewControllerTouch alloc]
initWithScope:[scopes componentsJoinedByString:#" "]
clientID:kClientID
clientSecret:nil
keychainItemName:kKeychainItemName
delegate:self
finishedSelector:#selector(viewController:finishedWithAuth:error:)];
return authController;
}
- (void)viewController:(GTMOAuth2ViewControllerTouch *)viewController
finishedWithAuth:(GTMOAuth2Authentication *)authResult
error:(NSError *)error {
if (error != nil) {
...
}
else {
NSLog(#"Access token: %#", authResult.accessToken);
}
}
And your ViewDidAppear method should looks like this:
- (void)viewDidAppear:(BOOL)animated {
if (!self.service.authorizer.canAuthorize) {
// Not yet authorized, request authorization by pushing the login UI onto the UI stack.
[self presentViewController:[self createAuthController] animated:YES completion:nil];
}
That code output the target access token.
I have trouble using [self isAuthorized] to get confirmation of the access token I've got earlier.
Every time I'm login in with Google Drive SDK for iOS with:
// Creates the auth controller for authorizing access to Google Drive.
-(GTMOAuth2ViewControllerTouch *)createAuthController {
GTMOAuth2ViewControllerTouch *authController;
authController = [[GTMOAuth2ViewControllerTouch alloc] initWithScope:scopes
clientID:kClientID
clientSecret:kClientSecret
keychainItemName:kKeychainItemName
delegate:self
finishedSelector:#selector(viewController:finishedWithAuth:error:)];
return authController;
}
After the authentification completed, there is no error so the access token should be saved correctly
// Handle completion of the authorization process, and updates the Drive service
// with the new credentials.
-(void)viewController:(GTMOAuth2ViewControllerTouch *)viewController finishedWithAuth:(GTMOAuth2Authentication *)authResult error:(NSError *)error {
if (error != nil)
{
//[self showAlert:#"Authentication Error" message:error.localizedDescription];
self.driveService.authorizer = nil;
}
else
{
self.driveService.authorizer = authResult;
}
}
I used an NSLog to make sure I received the access token and It did.
-(BOOL)isAuthorized {
NSString *oauthToken = [((GTMOAuth2Authentication *)self.driveService.authorizer) accessToken];
NSLog(#"oauthToken: %#", oauthToken);
return [((GTMOAuth2Authentication *)self.driveService.authorizer) canAuthorize];
}
But When I look if I'm authorized or not, there is no token saved (oauthToken is NULL) and I need to login again.
N.B: It was working in the past before iOS 9. I don't know if it is related.
Thanks
Vincent
You might want to try something like this to verify login:
// Check for authorization.
GTMOAuth2Authentication *auth =
[GTMOAuth2ViewControllerTouch authForGoogleFromKeychainForName:kKeychainItemName
clientID:kClientId
clientSecret:kClientSecret];
if ([auth canAuthorize]) {
[self isAuthorizedWithAuthentication:auth];
}
On the other hand, if you really want the access token, check out this SO post, however, it is not best practice to store the access token, since access token has an expiration time. Good luck & Hope this helps.
I am trying to implement Nest Thermostat in My Application i Can success fully create pin authentication code but
--->i struck in while storing that pin authentication code because after checking if condition if ([[url host] isEqualToString:[redirectURL host]]) then,
--->always condition fails if condition success then only i can store it and get access token by using it (as per library)
I did as per Nest Sample code and Library and online solutions no use I am looking for Picking hands
Plz Ref-fear my code
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{
NSURL *url = [request URL];
NSURL *redirectURL = [[NSURL alloc] initWithString:RedirectURL];
if ([[url host] isEqualToString:[redirectURL host]])
{
NSString *urlResources = [url resourceSpecifier];
urlResources = [urlResources stringByReplacingOccurrencesOfString:QUESTION_MARK withString:EMPTY_STRING];
urlResources = [urlResources stringByReplacingOccurrencesOfString:HASHTAG withString:EMPTY_STRING];
NSArray *urlResourcesArray = [urlResources componentsSeparatedByString:SLASH];
NSString *urlParamaters = [urlResourcesArray objectAtIndex:([urlResourcesArray count]-1)];
NSArray *urlParamatersArray = [urlParamaters componentsSeparatedByString:AMPERSAND];
NSString *keyValue = [urlParamatersArray lastObject];
NSArray *keyValueArray = [keyValue componentsSeparatedByString:EQUALS];
if([[keyValueArray objectAtIndex:(0)] isEqualToString:#"code"]) {
[self.delegate foundAuthorizationCode:[keyValueArray objectAtIndex:1]];
} else {
NSLog(#"Error retrieving the authorization code.");
}
return NO;
}
return YES;
}
The webview which is showing pin that is only screen i can see. after that i struck it .Desperately needed help
Use web base authentication and Fill the redirect url at the time of registering the client , this redirect url should not be empty on the client page,then once you enter the device login credentials into your app then it automatically redirect and gives the authentication token then with that authentication token access token will be provided , by using that access token you can get the device details
SHORT STORY
Using gtm-oauth2 for iOS and FOSOAuthServerBundle in Symfony2 to implement my own Oauth2 server I am not getting the callBack finishedSelector to be invoked.
This is where the "special" ViewController is created:
GTMOAuth2ViewControllerTouch * viewController;
viewController = [[GTMOAuth2ViewControllerTouch alloc] initWithAuthentication:myAuth
authorizationURL:authURL
keychainItemName:nil
delegate:self
finishedSelector:#selector(viewController:finishedWithAuth:error:)];
What are the reasons that might make finishedSelector, (the implemented method viewController:finishedWithAuth:error) not to be invoked?
The behavior I get is that the login page is properly rendered, but it acts as the starting point of the whole web application, rendering the rest of the pages once it is logged-in instead of returning the control to the finishedSelector and, finally, to the view controller that has to manage the continuation of the APP workflow.
LONG STORY
Using gtm-oauth2 and FOSOAuthServerBundle in Symfony2, I am experiencing problems trying to make the arquitecture to catch the login and load the authenticated session from my iOS APP.
I am following the instructions described in the gtm-oauth2 documentation, particularly the Signing in to non-Google Services part.
Doing what it is described there, I have this method for creating the auth object:
- (GTMOAuth2Authentication * ) authForMyAPP
{
//This URL is defined by the individual 3rd party APIs, be sure to read their documentation
NSString * url_string = #"http://myHost/oauth/v2/token";
NSURL * tokenURL = [NSURL URLWithString:url_string];
// We'll make up an arbitrary redirectURI. The controller will watch for
// the server to redirect the web view to this URI, but this URI will not be
// loaded, so it need not be for any actual web page. This needs to match the URI set as the
// redirect URI when configuring the app.
NSString * redirectURI = #"http://myHost/oauth/v2/falseCallBack";
GTMOAuth2Authentication * myAuth;
myAuth = [GTMOAuth2Authentication authenticationWithServiceProvider:#"MyAPP"
tokenURL:tokenURL
redirectURI:redirectURI
clientID:kMyClientID
clientSecret:kMyClientSecret
];
//[myAuth setTokenType:#"Bearer"];
return myAuth;
}
And then, this method creates the "special" viewController that should handle the render of the login page and returning the control when the login is performed:
- (void)signInToMyAPP()
{
GTMOAuth2Authentication *myAuth = [self authForMyAPP];
NSString* auth_string = #"http://127.0.0.1/~pgbonino/Symfony/web/app.php/oauth/v2/auth";
NSURL * authURL = [NSURL URLWithString:auth_string];
// Display the authentication view
// Creates the "special" viewController passing the `auth` object, the authorization URL and the finishedSelector
GTMOAuth2ViewControllerTouch * viewController;
viewController = [[GTMOAuth2ViewControllerTouch alloc] initWithAuthentication:myAuth
authorizationURL:authURL
keychainItemName:nil
delegate:self
finishedSelector:#selector(viewController:finishedWithAuth:error:)];
[self.navigationController pushViewController:viewController animated:YES];
}
Finally, I have the method used for that finishedSelector. It should be called once the login is properly performed and the authentication has succeeded (or an error has come). THAT IS WHAT I AM NOT GET DONE:
- (void)viewController:(GTMOAuth2ViewControllerTouch *)viewController
finishedWithAuth:(GTMOAuth2Authentication *)myAuth
error:(NSError *)error
{
if (error != nil)
{
// Authentication failed
UIAlertView *alertView = [ [UIAlertView alloc] initWithTitle:#"Authorization Failed"
message:[error localizedDescription]
delegate:self
cancelButtonTitle:#"Dismiss"
otherButtonTitles:nil];
[alertView show];
}
else
{
// Authentication succeeded
// Assign the access token to the instance property for later use
//self.accessToken = myAuth.accessToken;
[myAuth setShouldAuthorizeAllRequests:YES];
[[Singleton sharedSingleton] setAuth:myAuth];
// Display the access token to the user
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Authorization Succeeded"
message:[NSString stringWithFormat:#"Access Token: %#", myAuth.accessToken]
delegate:self
cancelButtonTitle:#"Dismiss"
otherButtonTitles:nil];
[alertView show];
}
}
This all is supposed to render my login page in a web view and catch the successful login to call the viewController:finishedWithAuth:error and save the session in some shared object.
Nevertheless, the behavior I am getting is that I get rendered the login in the web view, I correctly login and, instead oF the delegated selector gets invoked, it just normally logs in the application and the next page is loaded in the web view, as if it was in a normal browser. So the callback is not performed.
Why am I not getting the selector to be called? Any idea?
IMPORTANT NOTE: the Oauth2 server works perfectly: if I call the token URL and the callBack url from Safari, everything works well. Tokens and auths codes are correctly saved in database.
Forget it.
It was just me.
OAuth2 won't work with Symfony2 and FOSUserBundle while this parameter is set to true in config.yml:
always_use_default_target_path: false
I am developing an app for SharePoint online and wanted to use the SharePoint Rest interfaces in my ios app. Can Some one please tell me the steps to use SharePoint Rest interfaces in iOS
I got it, below are the steps to be followed:
Include RestKit in your ios app.
Create a UIView in your home screen and load the login page.
load http: //server name/Pages/default.aspx in the UIWebView
In webViewDidFinished method find out the Fed Auth token and append it with the request URL
- (void)webViewDidFinishLoad:(UIWebView *)webView {
//Retrive HTTPOnly Cookie
NSHTTPCookieStorage *storage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
NSArray *cookiesArray = [storage cookies];
//Search for Fed Auth cookie
for (NSHTTPCookie *cookie in cookiesArray) {
if ([[cookie name] isEqualToString:#"FedAuth"]) {
/*** DO WHATEVER YOU WANT WITH THE COOKIE ***/
NSLog(#"Found FedAuth");
NSURL *url=[NSURL URLWithString:#"http://my server/_vti_bin/listdata.svc"];
RKClient *client = [RKClient clientWithBaseURL:url];
client.requestQueue.requestTimeout = 10;
client.cachePolicy = RKRequestCachePolicyNone;
client.authenticationType = RKRequestAuthenticationTypeHTTPBasic;
client.username = #"username";
client.password = #"Password";
NSString *cookieVale=[cookie value];
NSString *getResourcePath=[#"?" stringByAppendingFormat:#"%#",cookieVale];
[client get:getResourcePath delegate:self];
break;
}
}
}
And here you can find the response.
- (void)request:(RKRequest *)request didLoadResponse:(RKResponse *)response {
id xmlParser = [[RKParserRegistry sharedRegistry] parserForMIMEType:RKMIMETypeXML];
NSError *error = nil;
id parsedResponse = [xmlParser objectFromString:[response bodyAsString] error:&error];
RKLogInfo(#"Parsed response : %#, error:%#",parsedResponse,error);
if ([response isSuccessful]) {
NSLog(#"%d",[response isCreated]);
// Response status was 200..299
if ([response isCreated] && [response isJSON]) {
// Looks like we have a 201 response of type application/json
RKLogInfo(#"The JSON is %#", [response bodyAsJSON]);
}
} else if ([response isError]) {
// Response status was either 400..499 or 500..599
RKLogInfo(#"Ouch! We have an HTTP error. Status Code description: %#", [response localizedStatusCodeString]);
}
}
The self accepted answer lost me lots of hours of trials and errors. It omits some key aspects like the fact that you also need to grab the rtFa cookie. And what's up with client.username = #"username" and client.password = #"Password" provided in the users code. What is that? Note that the client does not know the username or password at any moment...
AAAnyway, below is a great article which will guide you in the right direction:
http://www.codeproject.com/Articles/571996/Development-of-iPhone-client-application-for-Share
And this describes how to get the cookies without using a UIWebView
http://allthatjs.com/2012/03/28/remote-authentication-in-sharepoint-online/
Send the FedAuth cookie with all your subsequent Requests.
Once authenticated, you can call the REST API, documentation here:
http://msdn.microsoft.com/en-us/library/fp142385(v=office.15).aspx#bk_determining
When the user finish the sign in process towards a Office365 Sharepoint instance, the web view will be redirected in several steps. As one of the final steps before loading the actual Sharepoint web site, the web view will be asked to load "about:blank".
Detect when you web view starts loading "about:blank" and you know when the user finished the sign in process and can close the web view. Example code below.
// Load page in web view
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
NSLog(#"WebView should start loading %#", request.URL.absoluteString);
// Detect that the user finished the sign in process
if ([request.URL.absoluteString isEqualToString:#"about:blank"]) {
// Do your stuff here
return NO;
}
return YES;
}
The Sharepoint instance will also set the FedAuth cookie if the authentication was successful. The cookie must be included in future requests to the server.
You do not have to append the cookie manually, this will be taken care of by the URL loading system as long as the cookies has been accepted and stored in the NSHTTPCookieStorage and you are sending the request to the same server.
From Apple documentation
The URL loading system automatically sends any stored cookies
appropriate for an NSURLRequest. unless the request specifies not to
send cookies. Likewise, cookies returned in an NSURLResponse are
accepted in accordance with the current cookie acceptance policy.