Azure mobile: Client-directed login operation error (Facebook) - facebook

I am trying to use "Client-directed login operation" to authorize users with Facebook account on my azure-mobile service (http://msdn.microsoft.com/en-us/library/windowsazure/jj710106.aspx)
I downloaded and configured iOS Facebook SDK for the project;
Here is the code for user login:
NSArray* permissions = #[#"email, user_about_me, basic_info"];
[FBSession openActiveSessionWithReadPermissions:permissions
allowLoginUI:YES
completionHandler:^(FBSession* session, FBSessionState status, NSError* error) {
if (!error) {
[_msClient loginWithProvider:provider
token:#{#"access_token" : [[session accessTokenData] accessToken]}
completion:^(MSUser* user, NSError* error) {
NSLog(#"%#", error);
}];
}
}];
This code returns error:
Error Domain=com.Microsoft.WindowsAzureMobileServices.ErrorDomain Code=-1302 "Error: The Facebook Graph API access token authorization request failed with HTTP status code 400" UserInfo=0x1768ba80 {NSLocalizedDescription=Error: The Facebook Graph API access token authorization request failed with HTTP status code 400}
I can confirm, that
NSString* access_token = [[session accessTokenData] accessToken];
returns a valid access token, because it works here https://developers.facebook.com/tools/explorer/?method=GET&path=me without any errors.
What am I doing wrong?

Had a similar problem and I can confirm that the error returned by Azure Mobile Service is most unhelpful. I eventually read up about what's happening under the hood here: https://developers.facebook.com/docs/facebook-login/access-tokens/#extending
Then I tried to acquire the long-lived token by invoking a GET request manually (https://graph.facebook.com/oauth/access_token?grant_type=fb_exchange_token&client_id={app-id}&client_secret={app-secret}&fb_exchange_token={short-lived-token}) and here I finally got the real error message. In my case it turned out to be "The request is invalid because the app is configured as a desktop app" and simply flipping a switch in the Facebook app configuration fixed it.
In your case it might be a different error message, but I suggest you take this approach and see where it takes you.

This is old now but just had the same issue. Check that you don't have the "Is Your App Secret Embedded" switched on in. I had it on because I thought the ZUMO SDK would have it somewhere, but I guess it just lives on the cloud in your MS identity configuration.

Related

Is it possible for user of an ios app to like a URL on facebook using the facebook-sdk?

I am creating an iOS app where I want to allow the user to like a specific URL. I've tried to use the following code (as mentioned on the Facebook developers page) to like a specific url:
**- (IBAction)likeClicked:(UIButton *)sender {
SLAppDelegate *appDelegate = [[UIApplication sharedApplication]delegate];
[FBSession setActiveSession:appDelegate.session];
if (appDelegate.session.isOpen)
{
NSMutableDictionary<FBGraphObject> *action = [FBGraphObject graphObject];
action[#"object"] = #"http://samples.ogp.me/226075010839791";
[FBRequestConnection startForPostWithGraphPath:#"me/og.likes"
graphObject:action
completionHandler:^(FBRequestConnection *connection,
id result,
NSError *error) {
NSLog(#"Error %#",error.localizedDescription);
NSLog(#"result %#",result);
// handle the result
}];
}
}**
But the above code only allows me to like the URL if I am authorized as an admin of that app on the facebook developer page.
If I am not an admin to the app with that specific app id , I get an error description as following:
Error The operation couldn’t be completed. (com.facebook.sdk error` 5.)
There are different solutions given on Stack Overflow for this but none of them seem to be working for me. I've checked for permissions and I have added the "publish_actions" permission to permissions list.
Is there another reason why i might be getting this error?
Is there another workaround using which i can like a specific URL on facebook?
There would be couple of places to check
- Is your Facebook app under "sandbox mode", if it is you will have to turn it off once you are sure with your development.
If you have just created a FB graph action:
You are required to submit the action through the FB developer console and it usually takes couple days for them to approve, and once approved other users can start using the "like" action.
Until you get the action approved, only the App developers, testers and admins (on the FB developer site) for this particular app would be able to complete the action and see the results on their FB timeline.

iOS 6 - Facebook sharing procedure fails with error "The proxied app is not already installed"

Though, there is such a question Facebook Error (7) iOS 6 it's already closed without any answer!
While obtaining an access to user's facebook account I've got an error:
error is: Error Domain=com.apple.accounts Code=7 "The Facebook server could not fulfill this access request: The proxied app is not already installed." UserInfo=0xa260270 {NSLocalizedDescription=The Facebook server could not fulfill this access request: The proxied app is not already installed.}
I'm performing a request like this:
self.statusLabel.text = #"Waiting for authorization...";
if (self.accountStore == nil) {
self.accountStore = [[ACAccountStore alloc] init];
}
ACAccountType * facebookAccountType = [self.accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierFacebook];
NSDictionary * dict = #{ACFacebookAppIdKey : FB_APP_ID, ACFacebookAudienceKey : ACFacebookAudienceEveryone};
[self.accountStore requestAccessToAccountsWithType:facebookAccountType options:dict completion:^(BOOL granted, NSError *error) {
__block NSString * statusText = nil;
if (granted) {
statusText = #"Logged in";
NSArray * accounts = [self.accountStore accountsWithAccountType:facebookAccountType];
self.facebookAccount = [accounts lastObject];
NSLog(#"account is: %#", self.facebookAccount);
self.statusLabel.text = statusText;
[self postToFeed];
}
else {
self.statusLabel.text = #"Login failed";
NSLog(#"error is: %#", error);
}
}];
What does this error means?
I've solved this problem!
It was because I do not pass permissions array!
Though the ACAccountStore class states that this parameter is optional, it is not!
More over the application could launch and ask for basic permissions(as it is implied)!
So, you must always pass a permissions array.
Here's also a description of error codes returned by account store:
typedef enum ACErrorCode {
ACErrorUnknown = 1,
ACErrorAccountMissingRequiredProperty,
ACErrorAccountAuthenticationFailed,
ACErrorAccountTypeInvalid,
ACErrorAccountAlreadyExists,
ACErrorAccountNotFound,
ACErrorPermissionDenied,
ACErrorAccessInfoInvalid
} ACErrorCode;
(I've got ACErrorPermissionDenied here)
We had the same problem and after taking a closer look at the iOS facebook documentation ad
https://developers.facebook.com/docs/howtos/ios-6/
I noticed the following paragraph:
Note, to use iOS 6 native auth, apps need change the way they request permissions from users - apps must separate their requests for read and write permissions.
I must have read over that one several time but it contained the solution:
You have to do multiple request for access if you want to grant write (publish access). So now we first ask for permission 'email' to get read permission and then for 'publish_action' to be able to post to the timeline.
The error message is not clear since "app" could be your iOS app? Facebook.app on the phone? Facebook app? The "proxied app" is the Facebook app, and "not already installed" means, it's not yet been associated with the Facebook user online in terms of permissions.
The first time your Facebook app connects to the users Facebook account, you must specify the basic info value(s) in your ACFacebookPermissionsKey key of the options dictionary. Other Facebook SDK's past and present such as the Javascript or PHP libraries by default supply basic info as the key, so you never had to. It seems the native integration in iOS doesn't do this, thus, if when the user first connects your app to their Facebook account with no permissions supplied, you get this error.
After you are given access, i.e. - after the user is connected to the app in their privacy settings online, ACFacebookPermissionsKey does as Apple document, become optional.
It's all a little confusing when you start to try and use the native Facebook integration...
Using the native Facebook integration you must provide one of the following keys which are basic info keys: email, user_birthday, or user_location.
To quote Facebook (source):
To create this basic connection using the iOS 6 native Auth Dialog,
apps must request access to a user's basic profile information by
asking for one of email, user_birthday, or user_location permissions.
After experiencing this error on one of my devices (after seeing the correct, expected iOS alert view asking for me to approve Facebook access to my app):
'The Facebook server could not fulfill this access request: Invalid application ID.'
I finally found the problem.
Although it initially appears to be a problem with the Facebook app setup on the FB developer site it turned out that my device's iOS Facebook account no longer had a valid password associated with it - this can happy when users restore an iOS backup to a new device. Once I sorted that in my device settings everything worked as expected.
I've not experienced any problems requesting 'publish_stream' in the first FB permissions access request - I actually think the real problem here is that the error messages are so random that they don't help developers to locate the source of the errors we're experiencing thanks to Apple and Facebook's lack of unity!
A few more things that one can try other than the above suggestions is checking your app settings on facebook.com here -
https://developers.facebook.com/apps/<*APP_ID*>/summary
Make sure that the SandBox Mode is set to Off
Also,
Under "Select how your app integrates with Facebook"
Select-> Native iOS App
Set your Bundle ID
You can set any temporary integer value for iPhone/iPad App store ID
Set Facebook login to Enabled
Listed Platforms is Native iPhone App &/or Native iPad App
Save changes and try after some time as it might take a few minutes for facebook to sync the changes to all its servers.

DropBox IOS SDk retrieving access token and secret is invalid once user is Authenticated

Cross authentication of a dropbox user using Access token and secret not happening.
Elaborating my Question:
authenticate the user in my IOS app
In Ios app , I retrieve access token and secret from MPOAuthCredentialConcreteStore *credentials.
get the access token from credentials->acccessToken and similarly the secret.
Now if I feed these values into another app outside IOS which uses python sdk for dropbox. I get a error message "Invalid token".
But, interestingly the reverse process from step 1 to 4 works. i.e get access token and secret from python SDK and feed it to my IOS app by using
[dbSession updateAccessToken:#"xxxxxxxxx" accessTokenSecret:#"YYYYYYYYYYY" forUserId:#"12345678"];
and now i can assess user's dropbox account. Any idea as to whats going wrong? Is there a difference between MPoauth and Oauth? I believe MPoauth is just a wrapper right?
is there any other way to get the access token and secret?
Thanks for the help.
I found a fix for this. It was a simple error. Basically the editor I was using was adding a new line char at the end. For some one stuck at the same problem make sure you dont have a new line char at the end.
You can get your Access token by using this delegate
(BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *) url {
if ([[DBSession sharedSession] handleOpenURL:url]) {
if ([[DBSession sharedSession] isLinked]) {
// At this point you can start making API calls
NSLog(#"App linked successfully!");
}
// Add whatever other url handling code your app requires here
}
return NO;
}
Given url has Access token, secret token and user id

Error creating twitter ACAccount on iOS5: NSURLErrorDomain error -1012

I am having trouble creating and saving a new twitter account to ACAccountStore on iOS5.
After performing all the steps to init the account, ACAccountStore's saveAccount:withCompletionHandler: returns NSURLErrorDomain error -1012.
Does anyone have similar issues?
My code sample below is using requestToken to init ACAccountCrendential. This object is an OAToken (ShareKit object) initialized with the token and secret received from twitter after completing OAuth.
ACAccountStore *store = [[[ACAccountStore alloc] init] autorelease];
ACAccountType *twitterAccountType = [store accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter];
ACAccount *account = [[[ACAccount alloc] initWithAccountType:twitterAccountType] autorelease];
account.username = #"twitterusername";
account.credential = [[[ACAccountCredential alloc] initWithOAuthToken:requestToken.key tokenSecret:requestToken.secret] autorelease];
[store requestAccessToAccountsWithType:twitterAccountType withCompletionHandler:^(BOOL granted, NSError *error) {
if (granted) {
[store saveAccount:account withCompletionHandler:^(BOOL success, NSError *error) {
if (success) {
NSLog(#"TWITTER ACCOUNT CREATED SUCCESSFULLY!");
}
else{
NSLog(#"ERROR creating twitter account: %#", [error description]);
}
}];
}
}];
The strange thing is that Apple's Accounts Framework Reference suggests that saveAccount:withCompletionHandler: attempts to perform OAuth itself:
If the account type supports authentication and the account is not authenticated, the account is authenticated
using its credentials. If the authentication is successful, the account is saved; otherwise, it is not saved.
I find that very strange since there is no way for the user to authenticate directly with the server by inputting username/password.
I also tried to initialize ACAccountCredential with my application's consumer key and consumer secret, with the same result (failed with NSURLErrorDomain error -1012.)
Any guidance on this topic would be greatly appreciated!
thanks.
I'm having the same trouble adding a Twitter account with ACAccount. However, I was able to create a Twitter account with ACAccount successfully using an authorized OAuth Access token and Access token secret, not the Consumer key and Consumer secret. (dev.twitter.com/apps->Twitter->OAuth->OAuth Setting-->Access token and Access token secret) This means that you still have to use an OAuth library to get an authorized Access token and Access token secret when the user is adding a Twitter account.
Update: You can see how Twitter recommends that you migrate existing accounts to iOS5 system accounts here. That link provided me with the best example of how to add an ACAccount.

how to refresh an oauth token when using the Facebook iPhone SDK

I'm using the Facebook SDK for iOS in my app: http://github.com/facebook/facebook-ios-sdk
The oAuth token expires after about 2 hours. How can I "refresh" the oAuth token without having to call the [Facebook authorize...] method again - which shows an empty Facebook dialog briefly if the user had previously logged in? What I want to avoid is requiring the user to re-login to FB each time they use the app - say, day to day.
I am already saving / restoring oAuth tokens when the app exits / starts. And I can check to see if the token is valid using [Facebook isSessionValid], or by checking the expire time on the token. But what to do if the token has expired? I've read that it is possible to "refresh" the token, but I don't understand how this is done.
I don't want to request "offline_access" permission, which would give me a "forever" token.
Help!?
Facebook's implementation of OAuth doesn't support token refresh.
You have 2 types of access_tokens in Facebook. Short term token, which is given by default and a long term token which is given if you request offline_access. If refresh token were supported, it was the same as giving a offline_access token for all apps.
As long as the user has an active facebook session on your web control, you can request a new access_token just by accessing https://www.facebook.com/dialog/oauth?client_id=YOUR_APP_ID&redirect_uri=http://www.facebook.com/connect/login_success.html&response_type=token or probably some iOS SDK command that does the same (never worked with it so I can't tell). This kind of request will not ask the user to login again, but will use the previous session that was created during the first login.
Since none of these answers actually addressed the question I am going to detail how I have implemented OAuth token refresh using The Facebook SDK.
The SDK will automatically refresh your tokens when you make requests however, in my scenario we send the tokens to our servers and we need to use the latest token. So when our server indicates that we need new tokens this is what we do:
Note You can either pass the AppID into the FBSession or you can add the FacebookAppID key to your App's plist (this is what we do).
- (void)renewFacebookCredentials {
if (FBSession.activeSession.state == FBSessionStateOpen ||
FBSession.activeSession.state == FBSessionStateOpenTokenExtended) {
[self sessionStateChanged:[FBSession activeSession] state:[FBSession activeSession].state error:nil];
} else {
// Open a session showing the user the login UI
// You must ALWAYS ask for public_profile permissions when opening a session
[FBSession openActiveSessionWithReadPermissions:#[#"public_profile",#"email"]
allowLoginUI:NO
completionHandler:^(FBSession *session, FBSessionState state, NSError *error) {
//this block will run throughout the lifetime of the app.
[self sessionStateChanged:session state:state error:error];
}];
}
}
The you can use the sessionStateChanged: method that Facebook include in their documentation but a simplified handler looks like this:
- (void)sessionStateChanged:(FBSession *)session state:(FBSessionState) state error:(NSError *)error {
// If the session was opened successfully
NSString *accessToken;
if (!error && state == FBSessionStateOpen && [[session accessTokenData] accessToken]){
// Show the user the logged-in UI
//#see http://stackoverflow.com/questions/20623728/getting-username-and-profile-picture-from-facebook-ios-7
accessToken = [[session accessTokenData] accessToken];
//Now we have an access token, can send this to the server...
} else {
//No access token, show a dialog or something
}
//either call a delegate or a completion handler here with the accessToken
}
Be aware that some of the FBSession API calls check for thread affinity so I found that I had to wrap all my FBSession calls inside a dispatch_async(dispatch_get_main_queue(), ^{...
Just do [ [FBSession session] resume] if it return false do login again
Facebook iOS SDK doesn’t handle the session storage.
FBSessionDelegate is a callback interface that your application should implement. it's methods will be invoked on application's successful login or logout.
See the example application facebook-ios-sdk/sample/DemoApp/Classes/DemoAppViewController.m for fbDidLogin, fbDidNotLogin and fbDidLogout methods
As per the Facebook SDK documentation:
The Facebook SDK automatically refreshes the user's session if
necessary. When it does this, the state also transitions to the
FBSessionStateOpenTokenExtended state.
Also to further clarify (since SDK version 3.1):
The SDK refreshes session automatically on API calls.
It also refreshes the token data as needed when follow-on authentication or Facebook API calls made using the SDK.
As of today Facebook is supposed to refresh tokens automatically, requests to GraphAPI can be done without providing token string either (Facebook handles it under the hood).
Moreover, if it happens that user wasn't using app for a long time and his token managed to expire, on your next request to Graph API an alert will be shown by Facebook's SDK asking user to relogin (all that is handled by Facebook and when done - will return into FBSDKGraphRequest's closure).
However, if someone really has a reason to manually refresh access token, here's an example (Swift 4):
private var selfDestructableNotificationToken: NotificationTokenThatAutomaticallyRemovesObserver?
final class NotificationTokenThatAutomaticallyRemovesObserver: NSObject { // more info here: https://oleb.net/blog/2018/01/notificationcenter-removeobserver/
let token: Any
init(_ token: Any) { self.token = token }
deinit { NotificationCenter.default.removeObserver(token) }
}
...
if let currentFBToken = FBSDKAccessToken.current() { // if this is a Facebook user, not an email-based user
if FBSDKAccessToken.currentAccessTokenIsActive() { // and his token has not expired yet
let token = NotificationCenter.default.addObserver(forName: NSNotification.Name.FBSDKAccessTokenDidChange, object: nil, queue: OperationQueue.main) { notification in
if let userInfo = notification.userInfo, let refreshedToken = userInfo["FBSDKAccessToken"] as? FBSDKAccessToken {
self.fbAccessToken = refreshedToken.tokenString
} else {
self.fbAccessToken = currentFBToken.tokenString // falling back to using an old token (better than none)
}
}
self.selfDestructableNotificationToken = NotificationTokenThatAutomaticallyRemovesObserver(token)
FBSDKAccessToken.refreshCurrentAccessToken { _, _, error in
if let error = error {
print("failed to refresh Facebook token with error \(error.localizedDescription)")
self.fbAccessToken = currentFBToken.tokenString // falling back to an old token (better than none)
}
}
} else if FBSDKAccessToken.current().isExpired { // unlucky user. Probably returned to the app after > 2 months break
self.fbAccessToken = currentFBToken.tokenString // assigning expired token. Facebook will ask user to relogin as soon as we call Graph API with that expired token
}
}