Withings API - accessing protected resources - ios

I'm writing an iOS app that pulls Withings data and am using code from simple-oauth1 (which I previously used successfully to talk to the Fitbit API). I successfully obtained a request token, authenticated it, and then obtained an access token. Then I proceeded to make sure the groundwork was set for accessing protected resources by sending an oauthenticated GET request to http://wbsapi.withings.net/once?action=probe
I got an error code 0 (everything seems to be working...)
However when I try to make any other calls to http://wbsapi.withings.net, I'm confronted with error 250 ("The provided userid and/or Oauth credentials do not match").
Here is what the code looks like:
- (void)getUserInfo
{
NSString *path = #"measure";
NSMutableDictionary *moreParams = [[NSMutableDictionary alloc] init];
[moreParams setValue:#"getmeas" forKey:#"action"];
[moreParams setValue:#"1234567" forKey:#"userid"];
NSURLRequest *preparedRequest = [OAuth1Controller preparedRequestForPath:path
parameters:moreParams
HTTPmethod:#"GET"
oauthToken:self.oauthToken
oauthSecret:self.oauthTokenSecret];
[NSURLConnection sendAsynchronousRequest:preparedRequest
queue:NSOperationQueue.mainQueue
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
if (error) NSLog(#"Error in API request: %#", error.localizedDescription);
});
}];
}
This is how the request is being formatted (Christian's code in OAuth1Controller.m):
+ (NSURLRequest *)preparedRequestForPath:(NSString *)path
parameters:(NSDictionary *)queryParameters
HTTPmethod:(NSString *)HTTPmethod
oauthToken:(NSString *)oauth_token
oauthSecret:(NSString *)oauth_token_secret
{
if (!HTTPmethod
|| !oauth_token) return nil;
NSMutableDictionary *allParameters = [self standardOauthParameters].mutableCopy;
allParameters[#"oauth_token"] = oauth_token;
if (queryParameters) {
[allParameters addEntriesFromDictionary:queryParameters];
}
NSString *parametersString = CHQueryStringFromParametersWithEncoding(allParameters, NSUTF8StringEncoding);
NSString *request_url = API_URL;
if (path) request_url = [request_url stringByAppendingString:path];
NSString *oauth_consumer_secret = CONSUMER_SECRET;
NSString *baseString = [HTTPmethod stringByAppendingFormat:#"&%#&%#", request_url.utf8AndURLEncode, parametersString.utf8AndURLEncode];
NSString *secretString = [oauth_consumer_secret.utf8AndURLEncode stringByAppendingFormat:#"&%#", oauth_token_secret.utf8AndURLEncode];
NSString *oauth_signature = [self.class signClearText:baseString withSecret:secretString];
allParameters[#"oauth_signature"] = oauth_signature;
allParameters[#"oauth_signature_method"] = #"HMAC-SHA1";
NSString *queryString;
if (queryParameters) {
queryString = CHQueryStringFromParametersWithEncoding(queryParameters, NSUTF8StringEncoding);
}
if (queryString) {
request_url = [request_url stringByAppendingFormat:#"?%#", queryString];
}
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:request_url]];
request.HTTPMethod = HTTPmethod;
NSMutableArray *parameterPairs = [NSMutableArray array];
[allParameters removeObjectsForKeys:queryParameters.allKeys];
for (NSString *name in allParameters) {
NSString *aPair = [name stringByAppendingFormat:#"=\"%#\"", [allParameters[name] utf8AndURLEncode]];
[parameterPairs addObject:aPair];
}
NSString *oAuthHeader = [#"OAuth " stringByAppendingFormat:#"%#", [parameterPairs componentsJoinedByString:#","]];
[request setValue:oAuthHeader forHTTPHeaderField:#"Authorization"];
return request;
}
I'm sure I have the correct userid (redacted here as "1234567") but I'm not sure why I can't use it to pull data. I have a feeling this is where the code is breaking. Please help.

In this code section send "allParameters" instead of "queryParameters" in the time of creating the "queryString".Also before creating queryString remove #"OAuth-callback" key and its object from allParameters if added previously.check this link,hope it will work.
http://integratingwithings.blogspot.in/2014/05/withings-api-declassified-ios.html

Related

Error 403 on Youtube Video Upload IOS

In my project wanna have a flow like this:
Users record short videos -> they upload the videos on my channel -> end
To achive this result i'm trying to work with the new Google APIs Client Library for Objective-C for REST. It has a poor documentation and the examples are for mac only. Anyway after many errors this is my code:
- (void)doAuthWithoutCodeExchange:(OIDServiceConfiguration *)configuration
clientID:(NSString *)clientID
clientSecret:(NSString *)clientSecret {
NSURL *redirectURI = [NSURL URLWithString:kRedirectURI];
// builds authentication request
OIDAuthorizationRequest *request =
[[OIDAuthorizationRequest alloc] initWithConfiguration:configuration
clientId:clientID
clientSecret:clientSecret
scopes:#[ OIDScopeOpenID, OIDScopeProfile ]
redirectURL:redirectURI
responseType:OIDResponseTypeCode
additionalParameters:nil];
// performs authentication request
AppDelegate *appDelegate = (AppDelegate *) [UIApplication sharedApplication].delegate;
[self logMessage:#"Initiating authorization request %#", request];
appDelegate.currentAuthorizationFlow =
[OIDAuthorizationService presentAuthorizationRequest:request
presentingViewController:self
callback:^(OIDAuthorizationResponse *_Nullable authorizationResponse,
NSError *_Nullable error) {
if (authorizationResponse) {
OIDAuthState *authState =
[[OIDAuthState alloc] initWithAuthorizationResponse:authorizationResponse];
[self setAuthState:authState];
[self logMessage:#"Authorization response with code: %#",
authorizationResponse.authorizationCode];
// could just call [self tokenExchange:nil] directly, but will let the user initiate it.
OIDTokenRequest *tokenExchangeRequest =
[_authState.lastAuthorizationResponse tokenExchangeRequest];
[self logMessage:#"Performing authorization code exchange with request [%#]",
tokenExchangeRequest];
[OIDAuthorizationService performTokenRequest:tokenExchangeRequest
callback:^(OIDTokenResponse *_Nullable tokenResponse,
NSError *_Nullable error) {
if (!tokenResponse) {
[self logMessage:#"Token exchange error: %#", [error localizedDescription]];
} else {
[self logMessage:#"Received token response with accessToken: %#", tokenResponse.accessToken];
}
[_authState updateWithTokenResponse:tokenResponse error:error];
GTMAppAuthFetcherAuthorization *gtmAuthorization =
[[GTMAppAuthFetcherAuthorization alloc] initWithAuthState:authState];
// Sets the authorizer on the GTLRYouTubeService object so API calls will be authenticated.
self.youTubeService.authorizer = gtmAuthorization;
// Serializes authorization to keychain in GTMAppAuth format.
[GTMAppAuthFetcherAuthorization saveAuthorization:gtmAuthorization
toKeychainForName:kGTMAppAuthKeychainItemName];
[self uploadVideoFile];
}];
} else {
[self logMessage:#"Authorization error: %#", [error localizedDescription]];
}
}];
}
This method cause this flow:
app send user to google login page in safari -> user log with his credentials -> after login, user is redirect back to my app -> the block success call the method UploadVideo.
This part of the flow seems to work correctly, i obtain a valid token as the log says. The second part is the video upload that consist in two main methods:
- (void)uploadVideoFile {
// Collect the metadata for the upload from the user interface.
// Status.
GTLRYouTube_VideoStatus *status = [GTLRYouTube_VideoStatus object];
status.privacyStatus = #"public";
// Snippet.
GTLRYouTube_VideoSnippet *snippet = [GTLRYouTube_VideoSnippet object];
snippet.title = #"title";
NSString *desc = #"description";
if (desc.length > 0) {
snippet.descriptionProperty = desc;
}
NSString *tagsStr = #"tags";
if (tagsStr.length > 0) {
snippet.tags = [tagsStr componentsSeparatedByString:#","];
}
GTLRYouTube_Video *video = [GTLRYouTube_Video object];
video.status = status;
video.snippet = snippet;
[self uploadVideoWithVideoObject:video
resumeUploadLocationURL:nil];
}
- (void)uploadVideoWithVideoObject:(GTLRYouTube_Video *)video
resumeUploadLocationURL:(NSURL *)locationURL {
NSURL *fileToUploadURL = [NSURL fileURLWithPath:self.VideoUrlCri.path];
NSError *fileError;
NSLog(#"step");
if (![fileToUploadURL checkPromisedItemIsReachableAndReturnError:&fileError]) {
NSLog(#"exit");
return;
}
// Get a file handle for the upload data.
NSString *filename = [fileToUploadURL lastPathComponent];
NSString *mimeType = [self MIMETypeForFilename:filename
defaultMIMEType:#"video/mp4"];
GTLRUploadParameters *uploadParameters =
[GTLRUploadParameters uploadParametersWithFileURL:fileToUploadURL
MIMEType:mimeType];
uploadParameters.uploadLocationURL = locationURL;
GTLRYouTubeQuery_VideosInsert *query =
[GTLRYouTubeQuery_VideosInsert queryWithObject:video
part:#"snippet,status"
uploadParameters:uploadParameters];
query.executionParameters.uploadProgressBlock = ^(GTLRServiceTicket *ticket,
unsigned long long numberOfBytesRead,
unsigned long long dataLength) {
NSLog(#"upload progress");
};
GTLRYouTubeService *service = self.youTubeService;
_uploadFileTicket = [service executeQuery:query
completionHandler:^(GTLRServiceTicket *callbackTicket,
GTLRYouTube_Video *uploadedVideo,
NSError *callbackError) {
if (callbackError == nil) {
NSLog(#"uploaded");
} else {
NSLog(#"error %#",callbackError);
}
}];
}
- (NSString *)MIMETypeForFilename:(NSString *)filename
defaultMIMEType:(NSString *)defaultType {
NSString *result = defaultType;
NSString *extension = [filename pathExtension];
CFStringRef uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension,
(__bridge CFStringRef)extension, NULL);
if (uti) {
CFStringRef cfMIMEType = UTTypeCopyPreferredTagWithClass(uti, kUTTagClassMIMEType);
if (cfMIMEType) {
result = CFBridgingRelease(cfMIMEType);
}
CFRelease(uti);
}
return result;
}
I obtain a 403 error in NSLog(#"error %#",callbackError); and i can't see error details because the are something like :
data=<7b226572 726f7222 3a7b2265 72726f72 73223a5b 7b22646f 6d61696e 223a2267 6c6f6261 6c222c22 72656173 6f6e223a 22696e73 75666669 ... 61676522 3a22496e 73756666 69636965 6e742050 65726d69 7373696f 6e227d7d>}
In google api console i have created a Client Oauth for my application bundle and an API key, i use those values for my connection, it seems they works correctly because i obtain a valid token. Anyway, there someone who can help me or point me in the right direction about this error? Or there someone who knows a working example about a video upload for IOS and not for MAC ? There something weird in my code? I can't find any help in documentation or google

iOS client: I can have user sign into Active Directory, but how to access MS Graph API?

I'm developing an iOS app that needs to read User data from MS Azure Active Directory.
I have successfully followed some examples on iOS app from the MS Azure documentation and successfully brought up their authentication page and have the user signed in. What I get back is some user data in the form of a ADUserInformation object.
Here's is the code I have:
NSString *authority = #"https://login.microsoftonline.com/a5960f61-0bf9-4bf6-96cd-98c61d30XXXX/federationmetadata/2007-06/federationmetadata.xml";
NSString *resourceId = #"74cd2559-0389-4871-9904-bc767d71XXXX"; // (server)
NSString *clientId = #"c8a956a7-84b7-4050-875c-896aab6bXXXX"; //ios-client (us)
NSURL *redirectUri = [[NSURL alloc]initWithString:#"https://XXXXevents.azurewebsites.net/.auth/login/done"];
ADAuthenticationError *error;
ADAuthenticationContext * authContext = [ADAuthenticationContext authenticationContextWithAuthority:authority error:&error];
//authContext.parentController = parent;
[ADAuthenticationSettings sharedInstance].enableFullScreen = YES;
[authContext acquireTokenWithResource:resourceId
clientId:clientId
redirectUri:redirectUri
completionBlock:^(ADAuthenticationResult *result) {
if (result.status != AD_SUCCEEDED) {
NSLog(#"%#", result);
return;
}
else {
//save all of this information into core data
NSDictionary * payload = #{#"access_token" : result.tokenCacheItem.accessToken};
NSLog(#"%#", payload);
//#"aad"
//#"windowsazureactivedirectory"
[[QSActivityService defaultService].client loginWithProvider: #"aad"
token: payload
completion: ^(MSUser * _Nullable user, NSError * _Nullable error) {
NSLog(#"loginWithProvider-------");
if(!error) {
NSLog(#"YAY! %s - user: %# ", __FUNCTION__, user.userId);
ADUserInformation * temp = result.tokenCacheItem.userInformation;
[[CoreDataStack defaultStack] updateUserDetailFamilyName:temp.allClaims[#"family_name"]
version:temp.allClaims[#"ver"]
email:temp.allClaims[#"email"]
nbf:temp.allClaims[#"nbf"]
exp:temp.allClaims[#"exp"]
givenName:temp.allClaims[#"given_name"]
idp:temp.allClaims[#"idp"]
ipaddr:temp.allClaims[#"ipaddr"]
iss:temp.allClaims[#"iss"]
oid:temp.allClaims[#"oid"]
typ:temp.allClaims[#"typ"]
sub:temp.allClaims[#"sub"]
amr:temp.allClaims[#"amr"]
aud:temp.allClaims[#"aud"]
alg:temp.allClaims[#"alg"]
iat:temp.allClaims[#"iat"]
tid:temp.allClaims[#"tid"]
name:temp.allClaims[#"name"]
uniqueName:temp.allClaims[#"unique_name"]];
//other code, no problems here
MS Graph API
However, I would like access profile images, and all the other data. I have read that MS Graph API provides it, but I'm not sure how and where I would put the token.
Do I use the token from result.tokenCacheItem.accessToken? If so, in the header? or body?
Or do I simply hit up graph.windows.com twice. First time to get the Authentication Token, and second time for the data?
I have read a lot of documentation and none of them works as I keep getting the Token Missing or Malformed error message.
My Graph API code looks like this:
-(void)getUsersUsingAccessToken:(NSDictionary*)token completion:(void (^) (void))completion {
NSString * tenant = #"a5960f61-0bf9-4bf6-96cd-98c61d306f12";
NSString * accessToken = token[#"access_token"];
NSString * urlString = [NSString stringWithFormat: #"https://graph.windows.net/%#/tenantDetails?api-version=1.6", tenant];
NSString * httpVerb = #"POST";
//build an info object and convert to json
NSDictionary * bodyFormDict
= [NSDictionary dictionaryWithObjectsAndKeys:
#"client_credentials", #"grant_type",
#"https://graph.windows.net", #"resource",
#"c8a956a7-84b7-4050-875c-896aab6xxxx", #"client_id",
#"XLlZl69aUKiQTo4dpeiprItm+LYbDtpt6e9dn0bxxxx", #"client_secret",
nil];
NSError *error = nil;
//1st step
NSData * jsonInputData = [NSJSONSerialization dataWithJSONObject:bodyFormDict
options:NSJSONWritingPrettyPrinted
error:&error];
//2nd step
NSString * httpBodyString = [[NSString alloc]
initWithData:jsonInputData
encoding:NSUTF8StringEncoding];
NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
sessionConfiguration.allowsCellularAccess = YES;
self.session = [NSURLSession sessionWithConfiguration:sessionConfiguration];
NSMutableURLRequest * request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:urlString]];
request.HTTPMethod = httpVerb;
[request setValue: #"application/json; charset=utf-8" forHTTPHeaderField:#"Content-Type"];
[request setValue: accessToken forHTTPHeaderField:#"Authorization: Bearer"];
[request setHTTPBody:[httpBodyString dataUsingEncoding:NSUTF8StringEncoding]];
//asynchronous
NSURLSessionDataTask * getDataTask = [self.session dataTaskWithRequest:request
completionHandler:^(NSData * _Nullable data,
NSURLResponse * _Nullable response,
NSError * _Nullable error) {
//other code
}
If someone can provide working code sample using objective c to successfully retrieve data from the MS Graph API, it would be a great help.
Thanks for your time!
I believe the problem you are having is that the http header field isn't set correctly. Try this -
NSString *authValue = [NSString stringWithFormat:#"Bearer %#", accessToken];
[request setValue:authValue forHTTPHeaderField:#"Authorization"];
I found my answers in MS MSDN's starter projects and code samples
https://msdn.microsoft.com/en-us/office/office365/howto/starter-projects-and-code-samples
The specific project that helped me is this:
https://github.com/OfficeDev/O365-iOS-Microsoft-Graph-Profile
As you are going through that sample keep in mind:
Replace INSERT-AUTHORITY-HERE - the name of the tenant in which you provisioned your application. The format should be https://login.windows.net/(YourAzureUserName).onmicrosoft.com
I have found that
https://login.microsoftonline.com/YourAzureAccountID/federationmetadata/2007-06/federationmetadata.xml
also works
Replace INSERT-RESOURCE-ID-HERE - the ID for your mobile app backend. This is the Web API service app ID. NOT the native client iOS app.
Replace INSERT-CLIENT-ID-HERE - the client ID you copied from your iOS NATIVE client application. NOT the Web API service app.
Replace INSERT-REDIRECT-URI-HERE - your site’s /.auth/login/done endpoint, using the HTTPS scheme. This value should be similar to
#"https://XXXXXXXXXX.azurewebsites.net/.auth/login/done"
IF you have trouble importing the ADAL framework...
http://shanghaiseagull.com/index.php/2016/05/11/import-another-project-framework-into-your-project/
library can be found here: https://github.com/AzureAD/azure-activedirectory-library-for-objc
Hope it helps someone starting out...and please let me know if I can be of further help.

Twilio SDK voip call Invalid Uri

When I tried to make a call "name" to "name" via twilio I had this error :
pjsua_call.c .Dialog creation failed: Invalid URI (PJSIP_EINVALIDURI)
As I followed the twilio tutorial I have no idea why this error happen.
Any clue ?
Here the way I got the token (should be ok)
- (void)getTwilioToken{
NSString *urlString = [NSString stringWithFormat:#"http://foo.herokuapp.com/token?client=%#", [[[Utils getUserCredential] componentsSeparatedByString:#"|"] objectAtIndex:1]];
NSURL *url = [NSURL URLWithString:urlString];
NSError *error = nil;
NSString *token = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:&error];
if(token == nil){
NSLog(#"Error retrieving token: %#", [error localizedDescription]);
} else {
_phone = [[TCDevice alloc] initWithCapabilityToken:token delegate:self];
}
}
Here the code used to make the call :
-(IBAction)callResponder:(id)sender{
NSIndexPath *indexPath = [self.tableView indexPathForCell:sender];
NSString *responderEmail = [[self.responders objectAtIndex:indexPath.row] email];
NSDictionary *params = #{#"To": responderEmail};
//check if we can make an outgoing call and attempt a connection
NSNumber* hasOutgoing = [_phone.capabilities objectForKey:TCDeviceCapabilityOutgoingKey];
if ( [hasOutgoing boolValue] == YES ){
//Disconnect if we've already got a connection in progress
if(_connection){
[_connection disconnect];
}
_connection = [_phone connect:params delegate:self];
[_connection retain];
}
}
I also ran into this same issue myself. The problem pertained to how I set permissions for the Twilio token (using their Javascript API):
var capability = new twilio.Capability(twilioAccountSid, twilioAuthToken);
capability.allowClientOutgoing(twilioAppSid);
capability.allowClientIncoming(); // this is the problematic line
After I removed the (apparently incorrect) incoming permission setting line my device completed the call perfectly.

iOS Authenticate Azure Active Directory & get calendar events from office 365 exchange

Trying to Authenticate with Azure Active Directory and fetch mail, calendar data, accessToken is returned successfully:
authority = #"https://login.windows.net/common/oauth2/authorize";
redirectUriString = #"http://xxxxxx.xxxxxxx.com/oauth";
resourceId = #"https://outlook.office365.com";
clientId = #"xxxxxxx-xxxxx-xxx";
-(void) getToken : (BOOL) clearCache completionHandler:(void (^) (NSString*))completionBlock;
{
ADAuthenticationError *error;
authContext = [ADAuthenticationContext authenticationContextWithAuthority:authority
error:&error];
[authContext setValidateAuthority:YES];
NSURL *redirectUri = [NSURL URLWithString:redirectUriString];
if(clearCache){
[authContext.tokenCacheStore removeAllWithError:&error];
if (error) {
NSLog(#"Error: %#", error);
}
}
[authContext acquireTokenWithResource:resourceId
clientId:clientId
redirectUri:redirectUri
completionBlock:^(ADAuthenticationResult *result) {
if (AD_SUCCEEDED != result.status){
// display error on the screen
[self showError:result.error.errorDetails];
}
else{
completionBlock(result.accessToken);
}
}];
}
-(NSArray*)getEventsList
{
__block NSMutableArray * todoList;
[self getToken:YES completionHandler:^(NSString* accessToken){
NSURL *todoRestApiURL = [[NSURL alloc]initWithString:#"https://outlook.office365.com/api/v1.0/me/folders/inbox/messages?$top=2"];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc]initWithURL:todoRestApiURL];
NSString *authHeader = [NSString stringWithFormat:#"Bearer %#", #""];
[request addValue:authHeader forHTTPHeaderField:#"Authorization"];
[request addValue:#"application/json; odata.metadata=none" forHTTPHeaderField:#"accept"];
[request addValue:#"fbbadfe-9211-1234-9654-fe435986a1d6" forHTTPHeaderField:#"client-request-id"];
[request addValue:#"Presence-Propelics/1.0" forHTTPHeaderField:#"User-Agent"];
//[request addValue:#"true" forHTTPHeaderField:#"return-client-request-id"];
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
[NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if (error == nil){
NSArray *scenarios = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
todoList = [[NSMutableArray alloc]initWithArray:scenarios];
//each object is a key value pair
NSDictionary *keyVauePairs;
for(int i =0; i < todoList.count; i++)
{
keyVauePairs = [todoList objectAtIndex:i];
NSLog(#"%#", keyVauePairs);
}
}
NSLog(#"Finished");
//[delegate updateTodoList:TodoList];
}];
}];
return nil; }
Error is returned in response object:
{
error = {
code = ErrorAccessDenied;
message = "Access is denied. Check credentials and try again.";
};
}
I know its late to answer this but it might be helpful for someone like me who was struggling to get the same thing done
I have done this using the office 365 SDK for iOS which has all the inbuilt classes to do your work.
If you download their sample code it will provide you all the details you require to do certain operations (mail, calendar, contacts, one drive).
Before using the SDK make sure you login to Azure AD and register your application and add permissions so that you do not get 403 error code or any access denied message.
I am using the below code to fetch my events details from outlook calendar
[self getClientEvents:^(MSOutlookClient *client) {
NSURLSessionDataTask *task = [[[client getMe] getEvents] read:^(NSArray<MSOutlookEvent> *events, MSODataException *error) {
if (error==nil) {
if (events.count!=0) {
dispatch_async(dispatch_get_main_queue(), ^{
for(MSOutlookEvent *calendarEvent in events){
NSLog(#"name = %#",calendarEvent.Subject);
}
});
}else{
NSLog(#"No events found for today");
}
}
}];
[task resume];
}];
getClientEvents is a method which gives call to the Office 365 SDK and fetches the event details of the user but it first fetches the token for the resource and then makes the call with the acquired token
-(void)getClientEvents : (void (^) (MSOutlookClient* ))callback{
[self getTokenWith : #"https://outlook.office365.com" :true completionHandler:^(NSString *token) {
MSODataDefaultDependencyResolver* resolver = [MSODataDefaultDependencyResolver alloc];
MSODataOAuthCredentials* credentials = [MSODataOAuthCredentials alloc];
[credentials addToken:token];
MSODataCredentialsImpl* credentialsImpl = [MSODataCredentialsImpl alloc];
[credentialsImpl setCredentials:credentials];
[resolver setCredentialsFactory:credentialsImpl];
[[resolver getLogger] log:#"Going to call client API" :(MSODataLogLevel *)INFO];
callback([[MSOutlookClient alloc] initWithUrl:#"https://outlook.office365.com/api/v1.0" dependencyResolver:resolver]);
}];
}
getTokenWith method fetches the token for a resource first and then with the acquired token makes the necessary calls to fetch the events, but before fetching the token it checks in the cache to see if there are any tokens available for the same resource.
// fetch tokens for resources
- (void) getTokenWith :(NSString *)resourceId : (BOOL) clearCache completionHandler:(void (^) (NSString *))completionBlock;
{
// first check if the token for the resource is present or not
if([self getCacheToken : resourceId completionHandler:completionBlock]) return;
ADAuthenticationError *error;
authContext = [ADAuthenticationContext authenticationContextWithAuthority:[[NSUserDefaults standardUserDefaults] objectForKey:#"authority"] error:&error];
NSURL *redirectUri = [NSURL URLWithString:#"YOUR_REDIRECT_URI"];
[authContext acquireTokenWithResource:resourceId
clientId:[[NSUserDefaults standardUserDefaults] objectForKey:#"clientID"]
redirectUri:redirectUri
completionBlock:^(ADAuthenticationResult *result) {
if (AD_SUCCEEDED != result.status){
[self showError:result.error.errorDetails];
}
else{
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setObject:result.tokenCacheStoreItem.userInformation.userId forKey:#"LogInUser"];
[userDefaults synchronize];
completionBlock(result.accessToken);
}
}];
}
getCacheToken method: Checks if there are any reusable token for any resources.
-(BOOL)getCacheToken : (NSString *)resourceId completionHandler:(void (^) (NSString *))completionBlock {
ADAuthenticationError * error;
id<ADTokenCacheStoring> cache = [ADAuthenticationSettings sharedInstance].defaultTokenCacheStore;
NSArray *array = [cache allItemsWithError:&error];
if([array count] == 0) return false;
ADTokenCacheStoreItem *cacheItem;
for (ADTokenCacheStoreItem *item in array) {
if([item.resource isEqualToString:resourceId]){
cacheItem = item;
break;
}
}
ADUserInformation *user = cacheItem.userInformation;
if(user == nil) return false;
if([cacheItem isExpired]){
return [self refreshToken:resourceId completionHandler:completionBlock];
}
else
{
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setObject:user.userId forKey:#"LogInUser"];
[userDefaults synchronize];
completionBlock(cacheItem.accessToken);
return true;
}
}
Using this code and Office 365 SDK in place you can get the outlook events for a particular user, before that make sure you have full permissions in the Azure AD else you may get 0 events as response.
Please note all the methods are from the SDK example apart from the first method to view how to fetch the events i would recommend to download the exchange example from the github.
You can also use MSGraph SDK to fetch calendars and events:
Check this link: Configuration process is same, only fetching events is different(see given code for fetching events):
How to Fetch/Create calender by O365-iOS-Connect?
Note: Above link is used to fetch calendars from outlook the process is same for this but you should use this code after authentication and completed get events action look like this:
- (IBAction)getCalendarsEvents:(id)sender {
[NXOAuth2AuthenticationProvider setClientId:clientId
scopes:#[#"https://graph.microsoft.com/Files.ReadWrite",
#"https://graph.microsoft.com/Calendars.ReadWrite"]];
[[NXOAuth2AuthenticationProvider sharedAuthProvider] loginWithViewController:nil completion:^(NSError *error) {
if (!error) {
[MSGraphClient setAuthenticationProvider:[NXOAuth2AuthenticationProvider sharedAuthProvider]];
self.client = [MSGraphClient client];
// Authentication done
[[[[_client me] events] request] getWithCompletion:^(MSCollection *response, MSGraphUserEventsCollectionRequest *nextRequest, NSError *error){
NSArray *arr = response.value;
MSGraphEvent *event = arr.firstObject;
// Here you will getting outlook events
}];
}
}];
}

Client side IOS to Server using Braintree Payment Process

I'm using Braintree for Payment process in my application
[BTPaymentViewController paymentViewControllerWithVenmoTouchEnabled:NO];and use this method for encryption
`
(void)paymentViewController:(BTPaymentViewController *)paymentViewController
didSubmitCardWithInfo:(NSDictionary *)cardInfo
andCardInfoEncrypted:(NSDictionary *)cardInfoEncrypted {
NSDictionary *dict=[self encryptFormData:cardInfo];
[self savePaymentInfoToServer:dict];
}
-(NSDictionary *) encryptFormData:(NSDictionary *) formData {
BTEncryption *braintree = [[BTEncryption alloc] initWithPublicKey: PUBLIC_KEY];
NSMutableDictionary *encryptedParams = [[NSMutableDictionary alloc] init];
[formData enumerateKeysAndObjectsUsingBlock:^(id key, id object, BOOL *stop) {
[encryptedParams setObject: [braintree encryptString: object] forKey: key];
}];
return encryptedParams;
}
call to this method to post the data to localhost server for testing
- (void) savePaymentInfoToServer:(NSDictionary *)paymentInfo {
NSURL *url = [NSURL URLWithString: [NSString stringWithFormat:#"%#/card", SAMPLE_CHECKOUT_BASE_URL]];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
// You need a customer id in order to save a card to the Braintree vault.
// Here, for the sake of example, we set customer_id to device id.
// In practice, this is probably whatever user_id your app has assigned to this user.
// NSString *customerId = [[UIDevice currentDevice] identifierForVendor].UUIDString;
AppDelegate *appdelegate=(AppDelegate *) [[UIApplication sharedApplication]delegate];
[paymentInfo setValue:appdelegate.referenceId forKey:#"bookingRefId"];
[paymentInfo setValue:appdelegate.passengerId forKey:#"passengerId"];
request.HTTPBody = [self postDataFromDictionary:paymentInfo];
request.HTTPMethod = #"POST";
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response, NSData *body, NSError *requestError)
{
NSError *err = nil;
if (!response && requestError) {
NSLog(#"requestError: %#", requestError);
[self.paymentViewController showErrorWithTitle:#"Error" message:#"Unable to reach the network."];
return;
}
NSDictionary *<b>responseDictionary</b> = [NSJSONSerialization JSONObjectWithData:body options:kNilOptions error:&err];
NSLog(#"saveCardToServer: paymentInfo: %# response: %#, error: %#", paymentInfo, responseDictionary, requestError);
if ([[responseDictionary valueForKey:#"success"] isEqualToNumber:#1]) { // Success!
// Don't forget to call the cleanup method,
// `prepareForDismissal`, on your `BTPaymentViewController`
[self.paymentViewController prepareForDismissal];
// Now you can dismiss and tell the user everything worked.
[self dismissViewControllerAnimated:YES completion:^(void) {
[[[UIAlertView alloc] initWithTitle:#"Success" message:#"Saved your card!" delegate:nil
cancelButtonTitle:#"OK" otherButtonTitles:nil] show];
}];
} else { // The card did not save correctly, so show the error from server with convenenience method `showErrorWithTitle`
[self.paymentViewController showErrorWithTitle:#"Error saving your card" message:[self messageStringFromResponse:responseDictionary]];
}
}];
}`
contain responseDictionary is null and error is null how to fix the issue can any one help me
where are you sending the paymentInfo dictionary to (i.e. what is SAMPLE_CHECKOUT_BASE_URL)? The example project built by Braintree simulates a backend as if you had one yourself. You will want to replace that URL with your backend's URL.
The BTPaymentViewController provides a client-side credit card checkout page, but your backend still has to execute the transaction. For your backend to execute that transaction, you'll have to send that paymentInfo dictionary to your servers.
If you haven't yet built a backend for your iOS app, you can quickly get set up and approved in minutes with Braintree to process your payments.

Resources