working with the latest token sent in my web service - ios

I have a problem to find the latest token .. back end make the token change in every request so if I use it once it turned to be invalid in the next time, and they send the next valid token in Authorization header.
I am trying to get the latest token.
+(void)askServerUsingToken:(void (^)(NSDictionary * json,bool isSuccess))completionBlock{
// NSString* urlString = [NSString stringWithFormat:#"%#%#",baseURL,action];
//check token
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *token = [defaults stringForKey:#"token"];
if (token!= nil) {
NSString *finalyToken = [[NSString alloc]initWithFormat:#"%#",token];
NSString *profile=[NSString stringWithFormat:#"%#profile?token=%#",baseURL,finalyToken];
NSLog(#"%#",profile);
AFHTTPSessionManager *manager=[AFHTTPSessionManager manager];
manager.responseSerializer=[AFJSONResponseSerializer serializer];
[manager.requestSerializer setValue:finalyToken forHTTPHeaderField:#"Authorization"];
[manager GET:profile parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject){
dispatch_async(dispatch_get_main_queue(), ^{
// NSError *errorJson=nil;
// NSDictionary *jsonList=[NSJSONSerialization JSONObjectWithData:responseObject options:NSJSONReadingAllowFragments error:&errorJson];
NSDictionary *jsonList=(NSDictionary*)responseObject;
// completionBlock(jsonList,true);
if (jsonList !=nil) {
completionBlock(jsonList,true);
}else{
completionBlock(jsonList,false);
}
});
}failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error){
dispatch_async(dispatch_get_main_queue(),^{
completionBlock(nil,false);
});
}];
}else{
NSLog(#"no token");
}`enter code here`
}

Related

How to implement refresh token in ios

only some api call needs the token. and when 401 occurs refresh token call will be taken place.and for each call the token is refreshing. how to execute more than 1 api synchronously when 401 occurs
This is upto you, how you design the flow but I did almost same problem like following in Objective C
Call method of like in my case userProfileGETRequest
Before calling userProfileGETRequest Check date if token gets expired(in your case may be status code == 401)
If Token not expired simply call API in my case userProfileAPI with last token
If Token Expired then Call Refresh token and with Success and Failure Callback
If successful refresh token, call the userProfileAPI API with updated refresh token.
+ (void) userProfileGETRequest:(NSDictionary *)headerParams urlQuery: (NSString*)action parameters:(NSDictionary*)params docOpenPassword: (NSString*)password docOpenOtp: (NSString*)otp
onComplete:(void (^)(id json, id code, id url))successBlock
onError:(void (^)(id error, id code, id url))errorBlock {if ([[SingletonSDK sharedInstance] isTokenExpired:[NSDate date]]) {[self refereshToken:nil :^(id json, id code) {
[[SingletonSDK sharedInstance] handleLoginResponseObject:json];
[self userProfileAPI:headerParams urlQuery:action parameters:params
onComplete:^(id json, id code, id url) {
successBlock(json, code, url);
} onError:^(id error, id code, id url) {
errorBlock(error, code, url);
}];
} onError:^(id error, id code) {
[[SingletonSDK sharedInstance] hideProgessHud];
return ;
}];
}
} else {
[self userProfileAPI:headerParams urlQuery:action parameters:params
onComplete:^(id json, id code, id url) {
successBlock(json, code, url);
} onError:^(id error, id code, id url) {
errorBlock(error, code, url);
}];
}}
//userProfileAPI Methods
+ (void) userProfileAPI:(NSDictionary *)headerParams urlQuery: (NSString*)action parameters:(NSDictionary*)params
onComplete:(void (^)(id json, id code, id url))successBlock
onError:(void (^)(id error, id code, id url))errorBlock
{
NSString *authorizationValue = [self setAuthorizationValue:action];
NSString *language = [self editedLanguageNameAsApiRequired];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
//set headers values
[manager.requestSerializer setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[manager.requestSerializer setValue:language forHTTPHeaderField:#"Accept-Language"];
[manager.requestSerializer setValue:authorizationValue forHTTPHeaderField:#"authorization"];
[manager GET:action parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"getRequest response success");
NSString *url = [[[operation response] URL] absoluteString];
NSInteger statusCode = [operation.response statusCode];
NSNumber *statusObject = [NSNumber numberWithInteger:statusCode];
successBlock(responseObject, statusObject, url);
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
NSString *url = [[[operation response] URL] absoluteString];
NSInteger statusCode = [operation.response statusCode];
NSNumber *statusObject = [NSNumber numberWithInteger:statusCode];
if ([self takeDesiredActionIfAccessTokenExpired:statusCode]) {
return ;
}
id responseObject = operation.responseData;
id json = nil;
id errorMessage = nil;
if ([statusObject integerValue] == 404) {
errorMessage = [[SingletonSDK sharedInstance] getStringValueFromLanguageKey: COMMON_ERROR_SHARED_PREFERENCES];//NSLocalizedString(COMMON_ERROR_RESOURCE_NOT_FOUND, nil);
} else {
if (responseObject) {
json = [NSJSONSerialization JSONObjectWithData:responseObject options:kNilOptions error:&error];
errorMessage = [(NSDictionary*)json objectForKey:#"Message"];
}else{
json = [error.userInfo objectForKey:NSLocalizedDescriptionKey];
errorMessage = json;
}
}
if(![errorMessage isKindOfClass:[NSString class]]){
errorMessage = [[SingletonSDK sharedInstance] getStringValueFromLanguageKey: COMMON_ERROR_MSG] ; //NSLocalizedString(COMMON_ERROR_MSG, nil);
}
}];
}

Refresh access token automatically using AFOAuth2Manager

I have a server with OAuth 2.0 implemented for issuing access and refresh tokens. The client for this server is an iOS App written in Objective-C. I am currently using AFNetworking 3.0 for HTTP requests and AFOAuth2Manager to handle authorization. I want to refresh my access token stored in iOS app using the refresh token issued by the server before the access token expires (server returns number of seconds to expire as { 'expires_in': 3600 } (one hour)). Everything is working fine until the access token expires. Below is my code for handling requests and authorization.
- (AFJSONRequestSerializer *)setRequestSerializer
{
AFJSONRequestSerializer *serializer = [AFJSONRequestSerializer serializer];
[serializer setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[serializer setValue:#"application/json" forHTTPHeaderField:#"Accept"];
User *currentUser = [User currentUser];
if (currentUser){
AFOAuthCredential *credentials = [AFOAuthCredential retrieveCredentialWithIdentifier:kEndpointServer];
if (!credentials.isExpired){
[serializer setAuthorizationHeaderFieldWithCredential:credentials];
}
}
return serializer;
}
- (AFJSONResponseSerializer *)setResponseSerializer
{
AFJSONResponseSerializer *serializer = [AFJSONResponseSerializer serializer];
return serializer;
}
- (AFSecurityPolicy *)setSecurityPolicy
{
NSString *certFilePath = [[NSBundle mainBundle] pathForResource:#"cert" ofType:#"cer"];
NSData *certData = [NSData dataWithContentsOfFile:certFilePath];
NSSet *pinnedCerts = [NSSet setWithObject:certData];
AFSecurityPolicy *policy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate withPinnedCertificates:pinnedCerts];
[policy setAllowInvalidCertificates:YES]; // DEVELOPMENT ONLY
[policy setValidatesDomainName:NO];
return policy;
}
- (AFHTTPSessionManager *)sessionManager
{
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
manager.securityPolicy = [self setSecurityPolicy];
manager.requestSerializer = [self setRequestSerializer];
manager.responseSerializer = [self setResponseSerializer];
return manager;
}
- (AFOAuth2Manager *)OAuth2Manager
{
NSURL *baseURL = [NSURL URLWithString:kEndpointServer];
AFOAuth2Manager *manager = [[AFOAuth2Manager alloc] initWithBaseURL:baseURL clientID:kParamAPIClientId secret:kParamAPIClientSecret];
manager.securityPolicy = [self setSecurityPolicy];
return manager;
}
- (void)loginUser:(NSDictionary *)user block:(void (^)(BOOL, NSError *))result
{
// Set endpoint URL
NSString *loginEndpointURL = [NSString stringWithFormat:#"%#%#", kEndpointServer, kEndpointLogin];
AFHTTPSessionManager *manager = [self sessionManager];
if ([self internetConnectionAvailable]){
[manager POST:loginEndpointURL parameters:user progress:nil success:^(NSURLSessionDataTask *task, id responseObject){
NSDictionary *responseDict = (NSDictionary *)responseObject;
BOOL success = (BOOL)[(NSNumber *)[responseDict objectForKey:kParamSuccess] boolValue];
NSString *msg = (NSString *)[responseDict objectForKey:kParamMessage];
if (success){
// Get user
NSDictionary *userLoggedIn = (NSDictionary *)[responseDict objectForKey:kParamUser];
//NSLog(#"Logged in.");
NSString *tokenEndpointURL = [NSString stringWithFormat:#"/api%#%#", kEndpointOAuth, kEndpointToken];
OAuth2Manager *OAuth2Manager = [self OAuth2Manager];
[OAuth2Manager authenticateUsingOAuthWithURLString:tokenEndpointURL username:(NSString *)[user objectForKey:kParamEmail] password:(NSString *)[user objectForKey:kParamPassword] scope:nil success:^(AFOAuthCredential *credentials){
NSLog(#"Credentials:");
NSLog(#"Access Token: %#", credentials.accessToken);
NSLog(#"Refresh Token: %#", credentials.refreshToken);
// Store credentials
[AFOAuthCredential storeCredential:credentials withIdentifier:kEndpointServer];
// Set current user
[User setCurrentUser:userLoggedIn];
result(YES, nil);
}failure:^(NSError *error){
NSLog(#"Error authenticating user: %#", error);
result(NO, error);
}];
} else {
result(NO, [NSError errorWithDomain:msg code:kEDHTTPRequestFailedErrorCode userInfo:nil]);
}
}failure:^(NSURLSessionDataTask *task, NSError *error){
result(NO, error);
}];
} else {
result(NO, [NSError errorWithDomain:kEDNoInternetConnectionErrorDomain code:kEDNoInternetConnectionErrorCode userInfo:nil]);
}
}
I have found a similar question on SO:
How to automatically refresh expired token with AFOAuth2Manager?
But the problem with the answer given is that it is outdated (Works with AFNetworking 2.X.X, but does not work with AFNetworking 3.0).
What is the best practice for handling the refreshing of the access token automatically?

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);
}];
}

retry request when the internet connection is back - IOS

I am using AFNetworking 3.0 to perform Web request in my application.
Is there a way to automatically retry a request when the internet is back?
This is the request code:
#try {
NSString *urlMuniByGov = [NSString stringWithFormat:#"%#/%#", URL_MUNICIPALITES, selectedGov.govID];
NSURL *url = [NSURL URLWithString:urlMuniByGov];
AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] init];
manager.responseSerializer = [AFJSONResponseSerializer serializer];
manager.securityPolicy.allowInvalidCertificates = YES;
[manager GET:url.absoluteString
parameters:nil
progress:nil
success:^(NSURLSessionDataTask * task, id responseObject) {
NSArray *muniNSArray = [responseObject objectForKey:#"municipalites"];
if ([muniNSArray isKindOfClass:[NSArray class]]){
for (NSDictionary *dictionary in muniNSArray) {
Municipality *munModel = [Municipality new] ;
munModel.munID = [dictionary objectForKey:#"id"];
munModel.munNameAr = [[dictionary objectForKey:#"nom"] objectForKey:#"ar"];
munModel.munNameFr = [[dictionary objectForKey:#"nom"] objectForKey:#"fr"];
[self.munsArray addObject:munModel];
[self.munsString addObject:munModel.munNameAr];
}
}
[municipalityText setItemList:[NSArray arrayWithArray:self.munsString]];
} failure:^(NSURLSessionDataTask * task, NSError * error) {
NSLog(#"Error: %#", error);
}];
}
#catch (NSException *exception) {
NSLog(#"Exception: %#", exception);
}
[[AFNetworkReachabilityManager sharedManager]setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
NSLog(#"Reachability: %#", AFStringFromNetworkReachabilityStatus(status));}];
if any changes in the net connection this block will call , so here u can retry a request
for additional information follow the link https://github.com/AFNetworking/AFNetworking#network-reachability-manager

POST with URL parameters and JSON body in AFNetworking

I'd like to make a POST call that has both URL parameters and a JSON body:
URL http://example.com/register?apikey=mykey
JSON { "field" : "value"}
How can I use two different serializers at the same time with AFNNetworking? Here's my code with the URL parameters missing:
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.responseSerializer = [AFJSONResponseSerializer serializer];
[manager POST:#"http://example.com/register" parameters:json success:^(AFHTTPRequestOperation *operation, id responseObject) {
I make a post method
/**
* Services gateway
* Method get response from server
* #parameter -> object: request josn object ,apiName: api endpoint
* #returm -> void
* #compilationHandler -> success: status of api, response: respose from server, error: error handling
*/
+ (void)getDataWithObject:(NSDictionary *)object onAPI:(NSString *)apiName withController:(UIViewController*)controller
:(void(^)(BOOL success,id response,NSError *error))compilationHandler {
controller = controller;
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
// set request type to json
manager.requestSerializer = [AFJSONRequestSerializer serializer];
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
// post request to server
[manager POST:apiName parameters:object success:^(AFHTTPRequestOperation *operation, id responseObject) {
// NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:responseObject
options:0
error:&error];
//NSString *JSONString = [[NSString alloc] initWithBytes:[jsonData bytes] length:[jsonData length] encoding:NSUTF8StringEncoding];
////
// check the status of API
NSDictionary *dict = responseObject;
NSString *statusOfApi = [[NSString alloc]initWithFormat:#"%#"
,[dict objectForKey:#"OK"]];
// IF Status is OK -> 1 so complete the handler
if ([statusOfApi isEqualToString:#"1"] ) {
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
compilationHandler(TRUE,responseObject,nil);
} else {
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
NSArray *errorMessages = [responseObject objectForKey:#"messages"];
NSString *message = [errorMessages objectAtIndex:0];
[Utilities showAlertViewWithTitle:apiName message:message];
compilationHandler(FALSE,responseObject,nil);
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSString *message = [NSString stringWithFormat:#"%#",[error localizedDescription]];
NSLog(#"Message is %#", message);
NSString *errorMessage = [NSString stringWithFormat:#"%#",[error localizedDescription]];
if (!([message rangeOfString:#"The request timed out."].location == NSNotFound)) {
[Utilities showAlertViewWithTitle:apiName message:errorMessage];
}
compilationHandler(FALSE,errorMessage,nil);
}];
// For internet reachibility check if changes its state
[self checkInternetReachibility:manager];
}
**for Example when we call the Service **
// calling service gateway API
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:
"field",#"value",
nil];
[self getDataWithObject:dict onAPI:KGet_Preferences withController:(UIViewController*)controller :^(BOOL success, id response, NSError *error) {
if( success ) {
NSMutableDictionary *data = [[response valueForKey:#"data"] valueForKey:#"preferences"];
compilationHandler(success,data,error);
} else {
compilationHandler(success,nil,error);
}
}];
I believe there is no automatic way of doing it. However, there is a simple way of achieving it manually:
- (NSMutableURLRequest *)someRequestWithBaseURL:(NSString *)baseUrl
method:(NSString *)method
path:(NSString *)path
uriParameters:(NSDictionary *)uriParameters
bodyParameters:(NSDictionary *)bodyParameters
NSURL *url = [NSURL URLWithString:path relativeToURL:[NSURL URLWithString:baseUrl]];
AFHTTPRequestSerializer *httpRequestSerializer = [AFJSONRequestSerializer serializerWithWritingOptions:0]
NSMutableDictionary *parameters = [NSMutableDictionary dictionaryWithDictionary:bodyParameters];
if ([httpRequestSerializer.HTTPMethodsEncodingParametersInURI containsObject:method]) {
[parameters addEntriesFromDictionary:uriParameters];
} else {
NSURLComponents *urlComponents = [NSURLComponents componentsWithURL:url resolvingAgainstBaseURL:YES];
// For urlEncodedString, check http://stackoverflow.com/a/718480/856549
urlComponents.percentEncodedQuery = [uriParameters urlEncodedString];
url = [urlComponents URL];
}
NSError *error;
NSURLRequest *request = [httpRequestSerializer requestWithMethod:method
URLString:[url absoluteString]
parameters:parameters
error:&error];

Resources