Google Drive on iOS and "invalid_grant" - ios

I have an iOS app that uses Google Drive to sync some files. The app was working fine up until a couple of months ago (it uses iCloud by default for syncing so it wasn't until recently that I learned the Google Drive since was no longer working).
The error I'm getting is:
An error occurred: Error Domain=com.google.HTTPStatus Code=400 "(null)" UserInfo={json={
error = "invalid_grant";
}, data=<7b0a2020 22657272 6f722220 3a202269 6e76616c 69645f67 72616e74 220a7d>}
The OAuth part sets to be OK and I think I'm authorized to access the user's Google Drive. The error happens when I try to list the files at the top level to see if I need to create a special directory for my app.
- (void)createGoogleDocumentsDirIfNeeded:(id<GoogleServiceDelegate>)delegate
{
NSString *parentID = #"root";
GTLQueryDrive *query = [GTLQueryDrive queryForFilesList];
query.q = [NSString stringWithFormat:#"'%#' in parents and title = '%#' and trashed != true", parentID, APP_NAME];
[googleService executeQuery:query completionHandler:^(GTLServiceTicket *ticket,
GTLDriveFileList *files,
NSError *error)
{
if (error == nil)
{
if ( files.items.count == 0)
{
NSLog(#"Creating google documents dir: %#", APP_NAME);
[self createGoogleDocumentsDir:delegate];
}
else
{
GTLDriveFile *file = [files objectAtIndexedSubscript:0];
self.googleDocumentsID = file.identifier;
NSLog(#"Directory exists: %#; fileID = %#", APP_NAME, googleDocumentsID);
[delegate googleDocumentsDirCreated:YES];
}
}
else
{
NSLog(#"An error occurred: %#", error);
}
}];
}
The error is displayed in the last NSLog().
I'm pretty convinced that something has change on Google's side that is causing this. I've reverted to code to a point where I know it worked before and it is still failing.
Possibly I've made some change in our Google Developer's Console that is causing this, but I can't see what.
It is also the case that the Google API Dashboard still shows some successful accesses, so it seems this is not failing for everyone.
Any thoughts as to what could be going on? The "invalid_grant" error seems pretty generic and web searches show it happens in lots of situations. Any help would be appreciated.

As you say, there could be a variety of explanations.
Some to check are:-
has the user withdrawn his permission
are you using an expired refresh token
is the phone's clock accurate

Read https://developers.google.com/identity/protocols/OAuth2UserAgent
The URL used when authenticating a user is https://accounts.google.com/o/oauth2/v2/auth. This endpoint is accessible over SSL, and HTTP connections are refused.
Only for httpS connects for now

Related

Google Places for iOS version 3

Today Google released version 3 of its Places API for iOS. Upgrading my project and using the new findPlaceLikelihoodsFromCurrentLocationWithPlaceFieldsmethod I get the following error:
"Pick Place error The operation couldn’t be completed. An internal
error occurred in the Places API library...."
Any ideas?
Here is my complete Objective C code:
GMSPlaceField fields = GMSPlaceFieldName;
GMSPlacesClient *placesClient;
placesClient = [GMSPlacesClient sharedClient];
[placesClient findPlaceLikelihoodsFromCurrentLocationWithPlaceFields:fields callback:^(NSArray* likelihoods, NSError* error){
if(error != nil)
{
//##
NSLog(#"Pick Place error %#", [error localizedDescription]);
return;
}
for(GMSPlaceLikelihood *likelihood in likelihoods)
{
//##
NSLog(#"likelihood.place : %#",likelihood.place.name);
}
}];
Turns out Google changed things without being terribly obvious.
In my case, I used to have the "Places SDK for iOS" restriction added on the API key, but the new stuff requires the "Places API" restriction.

SoundCloud API iOS Fails to upload audio with a HTTP 422 error

I'm trying to put a super basic Soundcloud feature in my app to upload single .wav files using their UI. I followed their guide and I didn't really need anything outside of the bare bones share menu so I assumed this code would work:
NSURL *trackURL = [[NSURL alloc] initWithString:[docsDir stringByAppendingPathComponent:fileToShare]];
SCShareViewController *shareViewController;
shareViewController = [SCShareViewController shareViewControllerWithFileURL:trackURL
completionHandler:^(NSDictionary *trackInfo, NSError *error){
if (SC_CANCELED(error)) {
NSLog(#"Canceled!");
} else if (error) {
NSLog(#"Ooops, something went wrong: %#", [error localizedDescription
]);
} else {
// If you want to do something with the uploaded
// track this is the right place for that.
NSLog(#"Uploaded track: %#", trackInfo);
}
}];
// If your app is a registered foursquare app, you can set the client id and secret.
// The user will then see a place picker where a location can be selected.
// If you don't set them, the user sees a plain plain text filed for the place.
[shareViewController setFoursquareClientID:#"<foursquare client id>"
clientSecret:#"<foursquare client secret>"];
// We can preset the title ...
[shareViewController setTitle:#"Funny sounds"];
// ... and other options like the private flag.
[shareViewController setPrivate:NO];
// Now present the share view controller.
[self presentModalViewController:shareViewController animated:YES];
[trackURL release];
However I get an HTTP 422 error with this appearing in my debug console:
2016-02-29 11:04:47.129 synthQ[801:443840] parameters: {
"track[asset_data]" = "/var/mobile/Containers/Data/Application/EE58E5CA-B30C-44EB-B207-EB3368263319/Documents/bb.wav";
"track[downloadable]" = 1;
"track[post_to][]" = "";
"track[sharing]" = public;
"track[tag_list]" = "\"soundcloud:source=synthQ\"";
"track[title]" = "Funny sounds";
"track[track_type]" = recording;
}
2016-02-29 11:04:47.164 synthQ[801:444011] -[NXOAuth2PostBodyStream open] Stream has been reopened after close
2016-02-29 11:04:47.373 synthQ[801:443840] Upload failed with error: HTTP Error: 422 Error Domain=NXOAuth2HTTPErrorDomain Code=422 "HTTP Error: 422" UserInfo={NSLocalizedDescription=HTTP Error: 422}
Does anyone have any ideas what could be going wrong here?
Thanks!
One of the reason to get HTTP 422 error in SoundCloud is:
If you are trying to upload a file for a first time with a new account, you need to verify your email address to complete your SoundCloud registration in order to upload your files.
There might be other reasons for this error, however for my case it was the case and that solved the problem.
You cannot reference external resources while uploading tracks. You
therefor need to download the track to your computer and then perform
the actual upload to SoundCloud.
Source
Soundcloud file uploading issue HTTP 442
I managed to solve this by using a different constructor that passes the audio file as an NSData object:
shareViewController = [SCShareViewController shareViewControllerWithFileData:[NSData dataWithContentsOfFile:[docsDir stringByAppendingPathComponent:fileToShare]]
completionHandler:^(NSDictionary *trackInfo, NSError *error){
if (SC_CANCELED(error)) {
NSLog(#"Canceled!");
} else if (error) {
NSLog(#"Ooops, something went wrong: %#", [error localizedDescription
]);
} else {
// If you want to do something with the uploaded
// track this is the right place for that.
NSLog(#"Uploaded track: %#", trackInfo);
}
}];

mailcore2 imap Error Domain=MCOErrorDomain Code=5

I in turn to the making relevant mailcore2 problems, based on past errors, and all of the share, or didn't find the solution to this problem below, so the problem I have encountered redistribution, also hope to get more help, thank you!
Mailcore2 using the code below:
self.imapSession = [[MCOIMAPSession alloc] init];
self.imapSession.hostname = hostname;
self.imapSession.port = 993;
self.imapSession.username = username;
self.imapSession.password = password;
if (oauth2Token != nil) {
self.imapSession.OAuth2Token = oauth2Token;
self.imapSession.authType = MCOAuthTypeXOAuth2;
}
self.imapSession.connectionType = MCOConnectionTypeTLS;
MasterViewController * __weak weakSelf = self;
self.imapSession.connectionLogger = ^(void * connectionID, MCOConnectionLogType type, NSData * data) {
#synchronized(weakSelf) {
if (type != MCOConnectionLogTypeSentPrivate) {
NSLog(#"event logged:%p %i withData: %#", connectionID, type, [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
}
}
};
// Reset the inbox
self.messages = nil;
self.totalNumberOfInboxMessages = -1;
self.isLoading = NO;
self.messagePreviews = [NSMutableDictionary dictionary];
[self.tableView reloadData];
NSLog(#"checking account");
self.imapCheckOp = [self.imapSession checkAccountOperation];
[self.imapCheckOp start:^(NSError *error) {
MasterViewController *strongSelf = weakSelf;
NSLog(#"finished checking account.");
if (error == nil) {
[strongSelf loadLastNMessages:NUMBER_OF_MESSAGES_TO_LOAD];
} else {
NSLog(#"error loading account: %#", error);
}
strongSelf.imapCheckOp = nil;
}];
When I use iOS8.1 equipment, error message as follows, the console output:
checking account
2015-02-15 10:58:36.712 MailCoreTest[11971:2988194] event logged:0x166a4d50 0 withData: * OK [CAPABILITY IMAP4 IMAP4rev1 IDLE XAPPLEPUSHSERVICE ID UIDPLUS AUTH=LOGIN NAMESPACE] QQMail IMAP4Server ready
2015-02-15 10:58:36.821 MailCoreTest[11971:2988194] event logged:0x166a4d50 0 withData: (null)
2015-02-15 10:58:36.824 MailCoreTest[11971:2988128] finished checking account.
2015-02-15 10:58:36.825 MailCoreTest[11971:2988128] error loading account: Error Domain=MCOErrorDomain Code=5 "Unable to authenticate with the current session's credentials." UserInfo=0x16596ec0 {NSLocalizedDescription=Unable to authenticate with the current session's credentials.}
But when I use iOS8.0 devices, console to print the results are as follows:
checking account
2015-02-15 11:22:53.249 MailCoreTest[7853:1742121] finished checking account.
2015-02-15 11:22:53.249 MailCoreTest[7853:1742121] error loading account: Error Domain=MCOErrorDomain Code=1 "A stable connection to the server could not be established." UserInfo=0x17e50ab0 {NSLocalizedDescription=A stable connection to the server could not be established.}
Please help me, I contact with Objective - C time is short, but I must do my best to be aggressive, still hope to give a detailed solution, sincere thank you once again, hard work!
Yes its an authentication issue, I had same issue with my app but it was working fine before.
After I got this error, I checked my gmail account and there was an email from Google with subject "Suspicious Sign in prevented" and This sign in was of CA, USA. Actually My Application was under review so it was rejected for this reason.
Then I found that gmail is disabling unauthorised IPs.
You have to enable the 2 step verification for the gmail account to resolve this and generate an app specific password. Use that password in your app and It'll work fine.
Follow below google link to generate application specific password.
https://support.google.com/mail/answer/1173270?hl=en

Unable to obtain origin of NSLog in a Parse block?

I am using the following code to log in a user to my application using parse.com
[PFUser logInWithUsernameInBackground:usernameString password:passwordString
block:^(PFUser *user, NSError *error) {
if (user) {
// Do stuff after successful login.
NSLog(#"The user has logged in");
} else {
// The login failed. Check error to see why.
}
}];
The code works great and is documented on the Parse.com API Documentation HERE
My problem however is that I want to be able to show an alert to users when their login credentials come back with with an error, currently I get the following error on my console when I try to sign in with invalid credentials: Error: invalid login credentials (Code: 101, Version: 1.2.19)
Thats great, but I have looked everywhere and cant seem to find where that code, is being created... I am looking for it so that I can add different error messages for to my users: i.e.
if ([errorString rangeOfString:#"username"].location == NSNotFound) {
//the issue is not username related
} else
{
NSLog= (#"The username has been taken");
}
Any idea how I can find the string that contains the error and examine it so that I may act accordingly to the error?
the parse error codes are all documented here:
https://parse.com/docs/ios/api/Classes/PFConstants.html
101 is kPFErrorObjectNotFound
and means 'Object doesn't exist, or has an incorrect password.'
during a login it is likely more the later ;)
so:
if(error.code == kPFErrorObjectNotFound) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"parse login error" message:#"Invalid credentials" delegate:nil cancelButtonTitle:#"ok"];
[alert show];
}
dont use the error string of an NSError as you can't really tell if it is suitable for display.
still it is likely in localizedDescription or some other userInfo field
If you look at the documentation for NSError you will see that its userInfo property is a dictionary. From your NSLog you can see that the error key contains the string you are after, so you can access it with
NSString *errorMessage=[error.userInfo objectForKey:#"error"];
Although, rather than parsing strings it is safer to check the error.code value for 101, possibly displaying the error message for more detail. Checking the error code rather than the string will ensure that a change in the string by Parse won't break your code

Fetching Current User Profile using Objective C Google Plus Client Library

I am using the Google CLient Libraries for Objective C available here..
I have successfully been able to Authorize the user and get refresh token. (Using the GTMOAuthenticaion api embedded within).
In the Selector called after successful authorization I make the Get User Profile request as follows.. (I need the id of currently loggedin/authenticated user)
-(void)viewController:(GTMOAuth2ViewControllerTouch *)viewController
finishedWithAuth:(GTMOAuth2Authentication *)auth
error:(NSError *)error {
if (error != nil) {
NSLog(#"Stop");
} else {
if ([auth canAuthorize]){
[Mediator plusService].authorizer = auth;
// Problematic Line
GTLQueryPlus *profileQuery = [GTLQueryPlus queryForPeopleGetWithUserId:#"me"]; // Notice the UserId Param
profileQuery.completionBlock = ^(GTLServiceTicket *ticket, id object, NSError *error) {
if (error == nil) {
self.mediator.gProfile = object;
} else {
NSLog(#"GPlus Service Error %#", error);
}
};
[[Mediator plusService] executeQuery:profileQuery completionHandler:
^(GTLServiceTicket *ticket, id result, NSError *error) {
if (error)
NSLog(#"Some Service Error %#", error);
}];
}
}
}
If I put "me" as parameter, I get invalid user ID error string in jSON response.
However, If I provide some userId like my own 113632923069489732066 it works perfectly fine and returns the appropriate jSON response..!!
The Example for Google Plus inside Examples folder also fails to get current user profile ending with following error.
Error Domain=com.google.GTLJSONRPCErrorDomain Code=400 "The operation couldn’t be completed. (Invalid user ID: {0})" UserInfo=0x7a670fa0 {NSLocalizedFailureReason=(Invalid user ID: {0}), GTLStructuredError=GTLErrorObject 0x7a67b130: {message:"Invalid user ID: {0}" code:400 data:[2]}, error=Invalid user ID: {0}}
P.S. My API Console application doesn't work with iOS option under installed app but needs be configured with "Other" option. When configured with iOS option, the oAuth fails with invalid_client error response.
My Mistake .. !! And a very silly one .. !!
I was signing in using a Gmail Account that was yet not associated with GPlus .. !! =/

Resources