YouTube api v3 Invalid Credentials access token - ios

I am getting 401 Invalid Credentials error trying to use the Youtube API in the OAuth 2.0.
I used google sign in sdk and get access_token with params:
GIDSignIn *sharedSignIn = [GIDSignIn sharedInstance];
sharedSignIn.shouldFetchBasicProfile = NO;
sharedSignIn.scopes = [NSArray arrayWithObjects:
#"https://www.googleapis.com/auth/youtube.force-ssl",
#"https://www.googleapis.com/auth/youtube",
#"https://www.googleapis.com/auth/youtube.readonly",
// #"https://www.googleapis.com/auth/youtube.upload",
nil];
[sharedSignIn signIn];
Than I used AFNetworking library for GET request
- (void) getInformationWithParams: (NSDictionary *) params
method: (NSString *) method
onSuccess: (void(^)(NSDictionary *responseObject)) success
onFailure: (void (^) (NSError *error)) failure {
[self.requestOperationManager GET:method
parameters:params
progress:nil
success:^(NSURLSessionDataTask * _Nonnull task, NSDictionary *responseObject) {
NSLog(#"%#", responseObject);
if (success) {
success(responseObject);
}
}
failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSLog(#"getInformationWithParams Error: %#", error);
if (failure) {
failure(error);
}
}];
}
previously I did baseURL init
NSURL *baseURL = [NSURL URLWithString:#"https://www.googleapis.com/youtube/v3"];
self.requestOperationManager = [[AFHTTPSessionManager alloc] initWithBaseURL:baseURL];
and in the end I get request through
NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys:
#"snippet", #"part",
#"true", #"home",
myApiKey, #"key",
myAccessToken, #"access_token",
nil];
[[SMServerManager sharedManager] getInformationWithParams:params
method:#"activities"
onSuccess:^(NSDictionary *responseObject) {
}
onFailure:^(NSError *error) {
}];
I don't understand what I'm doing wrong.
PS: Requests work if they don't need to use acces_token.

It was a very stupid mistake. I'm confused in several google accounts and make wrong files for project.

Related

get authorization from Fitbit using Oauth in iOS

I want implement OAuth authentication for Fitbit to read the data from FitBit Api in my iOS app. I registered my app and i got clientId and client secret. I have been searched from past 2 days for tutorial, libraries. I am not any getting any idea about it. Please suggest me.
Note - According to https://dev.fitbit.com/docs/oauth2/
Applications should upgrade to OAuth 2.0 by March 14, 2016
Use safari or SFSafariViewController to open authorization page
Solution starts from here
please replace CLIENT_ID, REDIRECT_URI and other text to correct information
Point1-
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:#"https://www.fitbit.com/oauth2/authorize?response_type=code&client_id=CLIENT_ID&redirect_uri=REDIRECT_URI&scope=activity%20nutrition%20heartrate%20location%20nutrition%20profile%20settings%20sleep%20social%20weight"]];
give proper scheme url, so that after successful login you will be redirected to your application. In openURL method you will get a OAUTHCODE
Point2-
Now get OAUTHTOKEN by using this OAUTHCODE
-(void)toGetRequestToken:(id)sender
{
NSString *strCode = [[NSUserDefaults standardUserDefaults] valueForKey:#"auth_code"];
NSURL *baseURL = [NSURL URLWithString:#"https://www.fitbit.com/oauth2/authorize"];
AFOAuth2Manager *OAuth2Manager = [AFOAuth2Manager managerWithBaseURL:baseURL clientID:CLIENT_ID secret:CONSUMER_SECRET];
OAuth2Manager.responseSerializer.acceptableContentTypes = [OAuth2Manager.responseSerializer.acceptableContentTypes setByAddingObject:#"text/html"];
NSDictionary *dict = #{#"client_id":CLIENT_ID, #"grant_type":#"authorization_code",#"redirect_uri":#"Pro-Fit://fitbit",#"code":strCode};
[OAuth2Manager authenticateUsingOAuthWithURLString:#"https://api.fitbit.com/oauth2/token" parameters:dict success:^(AFOAuthCredential *credential) {
// you can save this credential object for further use
// inside it you can find access token also
NSLog(#"Token: %#", credential.accessToken);
} failure:^(NSError *error) {
NSLog(#"Error: %#", error);
}];
}
Point3-
now you can hit other FitBit requests like for "UserProfile" --
-(void)getFitbitUserProfile:(AFOAuthCredential*)credential{
NSURL *baseURL = [NSURL URLWithString:#"https://www.fitbit.com/oauth2/authorize"];
AFHTTPSessionManager *manager =
[[AFHTTPSessionManager alloc] initWithBaseURL:baseURL];
[manager.requestSerializer setAuthorizationHeaderFieldWithCredential:credential];
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
[manager GET:#"https://api.fitbit.com/1/user/-/profile.json"
parameters:nil progress:^(NSProgress * _Nonnull downloadProgress) {
} success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
NSDictionary *dictResponse = [NSJSONSerialization JSONObjectWithData:responseObject options:NSJSONReadingMutableContainers error:nil];
NSDictionary *userDict =[dictResponse valueForKey:#"user"];
NSLog(#"Success: %#", userDict);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSLog(#"Failure: %#", error);
}];
}

AFNetworking 3.x: How to know whether response is from cache or not?

The question AFNetworking : How to know if response is using cache or not ? 304 or 200 had been answered well for AFNetworking 2.x. But how do you do the same thing in 3.x?
It's very useful to know whether resources were returned from cache or from the network while debugging.
You can follow the same approach with AFNetworking3.0.
BOOL __block responseFromCache = YES; // yes by default
[self setDataTaskWillCacheResponseBlock:^NSCachedURLResponse * _Nonnull(NSURLSession * _Nonnull session, NSURLSessionDataTask * _Nonnull dataTask, NSCachedURLResponse * _Nonnull proposedResponse) {
responseFromCache = NO;
NSLog(#"Sending back to cache response");
NSCachedURLResponse * responseCached;
NSHTTPURLResponse * httpResponse = (NSHTTPURLResponse *) [proposedResponse response];
if (dataTask.originalRequest.cachePolicy == NSURLRequestUseProtocolCachePolicy) {
NSDictionary *headers = httpResponse.allHeaderFields;
NSString * cacheControl = [headers valueForKey:#"Cache-Control"];
NSString * expires = [headers valueForKey:#"Expires"];
if (cacheControl == nil && expires == nil) {
NSLog(#"Server does not provide info for cache policy");
responseCached = [[NSCachedURLResponse alloc] initWithResponse:dataTask.response
data:proposedResponse.data
userInfo:#{ #"response" : dataTask.response, #"proposed" : proposedResponse.data }
storagePolicy:NSURLCacheStorageAllowed];
}
}
return responseCached;
}];
[self wb_GET:url parameters:nil headerFields:additionalHeadersDict success:^(NSURLSessionDataTask *task, id responseObject) {
if (responseFromCache) {
// response was returned from cache
NSLog(#"RESPONSE FROM CACHE: %#", responseObject);
}
handler(responseObject, nil);
} failure:^(NSURLSessionDataTask *task, NSError *error) {
handler(nil, error);
}];
Besides that you can also implement below delegate method to your AFHTTPSessionManager subclass.
- (void)baseSuccessWithResponseObject:(id)responseObject sessionTask: (NSURLSessionDataTask *) task validationHandler:(void(^)(id responseObject, NSError *error))handler{}

iOS Run two asynchronous method if failed

I have a scenario where I need to quiet refresh auth token (relogin) again if it expired when I accessing other API but I'm having a hard time thinking how to code this without creating redundant codes for every APIs even though the flow is similar.
When user has expired auth token > call paid API A (return 401 unauthorised) > relogin again > call paid API A (run successfully)
I'm having difficult in wrapping my mind to call paid API A the second time with less code and not falling into infinite loop trap. Is there any method useful for this case like NSNotification center?
Note: I need to use API in this format from AFNetworkinglogin
- (NSURLSessionDataTask *)getApiA:(CallbackBlock)block{
CallbackBlock _block = [block copy];
NSString *urlString = [[NSURL URLWithString:GET_API_A_URL relativeToURL:[NSURL URLWithString:HOME_URL]] absoluteString];
return [self GET:urlString parameters:nil success:^(NSURLSessionDataTask *task, id responseObject) {
NSDictionary *response = (NSDictionary *)responseObject;
BLOCK_SAFE_RUN(block, response, nil, task);
} failure:^(NSURLSessionDataTask *task, NSError *error) {
if([self unauthorizedAccess:task]){ //401
***//call Login once again > run getApiA again***
}else if ([self forbiddenAccess:task]){ //403
}
BLOCK_SAFE_RUN(block, nil, error, task);
}];
}
If i get it right you could split it into 2 methods. And pass a bool for trying again. e.g.:
- (NSURLSessionDataTask *)getApiA:(id)block {
NSString *urlString = [[NSURL URLWithString:GET_API_A_URL relativeToURL:[NSURL URLWithString:HOME_URL]] absoluteString];
return [self doApiACallWithURL:urlString firstTry:YES completion:block];
}
- (NSURLSessionDataTask *)doApiACallWithURL:(NSString *)url firstTry:(BOOL)first completion:(CallbackBlock)completion {
__weak typeof(self) wself = self;
return [self GET:urlString parameters:nil success:^(NSURLSessionDataTask *task, id responseObject) {
NSDictionary *response = (NSDictionary *)responseObject;
BLOCK_SAFE_RUN(block, response, nil, task);
} failure:^(NSURLSessionDataTask *task, NSError *error) {
if ([wself unauthorizedAccess:task]) { //401
if (first) {
[wself doApiACallWithURL:url firstTry:NO completion:completion];
}
} else if ([wself forbiddenAccess:task]) { //403
}
BLOCK_SAFE_RUN(block, nil, error, task);
}];
}
and use a weak self for blocks is in most cases a good idea.

AFNetworking NSData - Incompatible block pointer types sending

I am trying to redo some code to use AFNetworking. I have this method below:
-(NSArray *)GetTableDataOfPhase:(NSString *)phase
{
NSString *phaseRequestString = [NSString stringWithFormat:#"%#?jobNo=%#",kIP,phase];
NSURL *JSONURL = [NSURL URLWithString:phaseRequestString];
NSURLResponse* response = nil;
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:JSONURL];
NSData* data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];
if(data == nil)
return nil;
NSError *myError;
NSArray *tableArray = [[NSArray alloc]initWithArray:[NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&myError]];
return tableArray;
}
and right now I am trying to alter it so it still returns an array, I have tried doing this:
-(NSArray *)GetTableDataOfPhase:(NSString *)phase
{
NSString *phaseRequestString = [NSString stringWithFormat:#"%#?jobNo=%#",kIP,phase];
NSURL *JSONURL = [NSURL URLWithString:phaseRequestString];
NSURLResponse* response = nil;
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:JSONURL];
AFHTTPRequestOperation *operation = [[[AFHTTPRequestOperation alloc] initWithRequest:request] autorelease];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSData* data = [NSURLConnection sendSynchronousRequest:responseObject returningResponse:&response error:nil];
if(data == nil)
return nil;
NSError *myError;
NSArray *tableArray = [[NSArray alloc]initWithArray:[NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&myError]];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
}];
[operation start];
return tableArray;
}
but I got this error:
/Users/jamessuske/Documents/My Programs/SSiPad(Device Only)ios7/SchedulingiPadApplication/Classes/LHJSonData.m:168:46: Incompatible block pointer types sending 'void *(^)(AFHTTPRequestOperation *, id)' to parameter of type 'void (^)(AFHTTPRequestOperation *, id)'
and this warning:
/Users/jamessuske/Documents/My Programs/SSiPad(Device Only)ios7/SchedulingiPadApplication/Classes/LHJSonData.m:170:97: Sending 'NSURLResponse *const *' to parameter of type 'NSURLResponse **' discards qualifiers
This is how I am calling it:
- (void)GetRequest
{
//refresh table view
[dataSource.editedCellHolder removeAllObjects];
[dataSource.cellHolder removeAllObjects];
[dataSource.cellHolderDisplay removeAllObjects];
NSArray *tableData = [dataSource.areaData GetTableDataOfPhase:[NSString stringWithFormat:#"%#%#",areaPickerSelectionString,unitPickerSelectionString]];
if(tableData == nil)
[self CustomAlert:#"Data was not recieved from the server, please check internet/VPN settings, Or contact Software Vendor for assistance."];
[dataSource PopulateTableData:tableData];
[indicatorView stopAnimating];
[indicatorView removeFromSuperview];
[loadingView removeFromSuperview];
loadingView = nil;
indicatorView =nil;
[NSTimer scheduledTimerWithTimeInterval:0.2f target:self selector:#selector(DisplayTable) userInfo:nil repeats:NO];
}
A couple of things:
Using AFNetworking, you should entirely lose the NSURLConnection request.
Likewise, the default responseSerializer does the JSON parsing for you, so you can lose the NSJSONSerialization parsing. AFNetworking does all of that for you.
Likewise, don't build URL parameters manually, but rather again let AFNetworking do that for you. By default, AFNetworking uses a requestSerializer that will build the request for you.
Your old method ran synchronously, which is generally a bad idea. Instead, you should use asynchronous patterns (e.g. a completionHandler block).
So, pulling all of this together, it probably looks like:
- (void)getTableDataOfPhase:(NSString *)phase completionHandler:(void (^)(NSArray *resultsObject, NSError *error))completionHandler
{
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
NSDictionary *parameters = #{#"jobNo" : phase};
[manager GET:kIP parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject) {
completionHandler(responseObject, nil);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
completionHandler(nil, error);
}];
}
And you'd call it like so:
[self getTableDataOfPhase:#"..." completionHandler:^(NSArray *resultsObject, NSError *error) {
if (resultsObject) {
// use NSArray here
} else {
NSLog(#"error = %#", error);
}
}];
// but don't try to use the `resultsObject` array here!

How to send a post request to api with user information without getting blank response.

I'm sending a NSMutalbeDictionary User with the correct information.
I have sending post using these two methods.
+ (void)loginUsers:(NSMutableDictionary*)user {
NSString *endpoint = #"api/users/sign_in";
[self postEndpoint:endpoint params:user completionBlock:^(TSystemsResponse *response) {
}];
}
+ (void)postEndpoint:(NSString *)endpoint params:(NSMutableDictionary *)params completionBlock:(void (^)(TSystemsResponse *response))completionBlock {
[[TSystemsAPIClient sharedClient] postPath:[NSString stringWithFormat:#"/%#", endpoint] parameters:params success:^(AFHTTPRequestOperation *request, id responseObject) {
TSystemsResponse *resp = [[TSystemsResponse alloc] initWithDictionary:responseObject];
completionBlock(resp);
} failure:^(AFHTTPRequestOperation *request, NSError *error) {
NSLog(#"Request to /%# FAILED: %#", endpoint, error);
completionBlock(nil);
}];
}
I'm getting a response from the server that says the following
{
"success": false,
"message": "Missing user parameter"
}
So i'm thinking that I'm not sending the information through correctly. The API call works in Post man.
Double check the params variable actually has the key "user" and not uppercased:
NSLog(#"%#", params);
[self postEndpoint:endpoint params:params completionBlock:nil];
If that is not the case you have to show us the innards of TSystemsAPIClient postPath:parameters:success: method.

Resources