Facebook iOS SDK won't open login UI after user changes password (iOS 6) - facebook-ios-sdk

Some context: the user had previously installed the app, authorized FB, everything worked great, then they changed their FB password (through facebook.com), deleted the app, and have now reinstalled it and are running it for the first time again after reinstall.
I am calling [FBSession openActiveSessionWithReadPermissions:allowLoginUI:completionHandler] with allowLoginUI: YES and the read permissions being "email, user_about_me, user_birthday, user_interests, user_location."
The FBSessionState I am getting in the completionHandler is FBSessionStateClosedLoginFailed. The NSLog of the error is this:
Error Domain=com.facebook.sdk Code=2 "The operation couldn’t be completed. (com.facebook.sdk error 2.)" UserInfo=0x1cd68c00 {com.facebook.sdk:ErrorLoginFailedReason=com.facebook.sdk:ErrorLoginFailedReason, com.facebook.sdk:ErrorInnerErrorKey=Error Domain=com.apple.accounts Code=7 "The Facebook server could not fulfill this access request: Error validating access token: The session has been invalidated because the user has changed the password." UserInfo=0x1cd5b970 {NSLocalizedDescription=The Facebook server could not fulfill this access request: Error validating access token: The session has been invalidated because the user has changed the password.}}
That internal error domain is ACErrorDomain and error code ACErrorPermissionDenied. So, how do I let the user re-authorize the app?
I have tried calling openActiveSessionWithReadPermissions again but that just keeps outputting the same error. I have also tried [FBSession.activeSession closeAndClearTokenInformation] but that doesn't seem to do anything (presumably because there is no activeSession).

Hitting a very similar sort of bug with 3.2.1 Facebook SDK. In my case, I get into FBSessionStateOpen but have been given an invalid access token. As the question states, the normal closeAndClearTokenInformation and even deleting the app doesn't fix it. The only way I have been able to get-back-in under this scenario is to have the user change their password in the setting app. So this is what I do.
// In my completion handler FBSessionStateOpen is called BUT an
// invalid accessToken was detected.
[session closeAndClearTokenInformation];
[FBSession renewSystemCredentials:^(ACAccountCredentialRenewResult result,
NSError *error)
{
if (result == ACAccountCredentialRenewResultFailed ||
result == ACAccountCredentialRenewResultRejected)
{
[self showErrorMessage:NSLocalizedString(#"You may need to re-enter your Facebook password in the iPhone Settings App.\n", nil)];
}
else
{
// attempt opening a session again (after they have updated their account
// settings I end up here)
[self facebookLogin]; // Performs openActiveSessionWithReadPermissions,
// but this time around the token issued should be good.
}
}];
This is the only pragmatic solution I have been able to come up with.

I think you need to get a new access token with code like this...
[FBSession.activeSession closeAndClearTokenInformation];
[[FBSession class] performSelector:#selector(renewSystemAuthorization)];
[FBSession openActiveSessionWithReadPermissions:nil
allowLoginUI:YES
completionHandler:^(FBSession *session, FBSessionState state, NSError *error) {
}

Related

Microsoft Graph returning null account even after passing a valid account ID

I am encountering a weird issue with Microsoft Graph on an integration that was built a few years back.
This issue started happening a few months back. After I sync a Microsoft Account and provide email and calendar read/write access, everything works fine for some time. I am able to retrieve emails and calendar events. However, after some time, I notice that when a call is made to GetAccountAsync with a valid AccountID, null is returned. This is causing AcquireTokenSilent to fail with the following error:
Error Code: user_null
Error Message: No account or login hint was passed to the AcquireTokenSilent call.
I have also noticed that this happens under the following scenarios:
When the WebJob (console app) is run every 15 minutes, I encounter this issue
To narrow down the root cause, I have deleted the WebJob to see if the issue occurs on the web app. It looks like the issue starts to occur after an hour or so even without the web job running.
I have upgraded to the latest version of MSAL and implemented 4.46.1.0 version of Microsoft.Identity.Client. I am using .NET Framework 4.8 and this is a .NET MVC 5 app.
Here's my code:
public async Task<string> GetAccessTokenAsync()
{
string accessToken;
UserExternalApp.Scope = string.IsNullOrWhiteSpace(UserExternalApp.Scope) ? "" : UserExternalApp.Scope;
// Load the app config from web.config
var microsoftScopes = UserExternalApp.Scope.Replace(' ', ',').SplitAndTrim(new char[] { ',' }).ToList();
var accountID = UserExternalApp.ExternalUserAccountID;
var app = ConfidentialClientApplicationBuilder.Create(ClientID)
.WithRedirectUri(DefaultRedirectUrl) // https:\//mywebsite.com
.WithClientSecret(Secret)
.Build();
app.AddDistributedTokenCache(services =>
{
services.AddDistributedSqlServerCache(options =>
{
options.ConnectionString = System.Configuration.ConfigurationManager.ConnectionStrings["Connection"].ConnectionString;
options.SchemaName = "dbo";
options.TableName = "TokenCache";
options.DefaultSlidingExpiration = TimeSpan.FromMinutes(90);
});
});
try
{
var account = await app.GetAccountAsync(accountID);
var query = app.AcquireTokenSilent(microsoftScopes, account); // This is where the error is thrown
var acquireTokenSilent = await query.ExecuteAsync();
accessToken = acquireTokenSilent.AccessToken;
}
catch
{
// This is the error thrown:
// Exception Type: MsalUiRequiredException
// Error code: user_null
// Exception Details: No account or login hint was passed to the AcquireTokenSilent call.
throw;
}
return accessToken;
}
I know the token is persisted on my SQL Server:
I think the MSAL uses an in memory token cache by default, Once the client logins, authentication information will be stored in cookie(if cookie has not been disabled). Even your web application restarts, the client will keep logged in.
To solve this, you can use custom Token cache serialization in MSAL.NET:https://learn.microsoft.com/en-us/azure/active-directory/develop/msal-net-token-cache-serialization?tabs=aspnet.
Hope this helps.
I would like to share the resolution to this problem in case if it helps someone in the future. I feel that this is a Microsoft Bug that was introduced during one of their many upgrade process as this code went from working to broken without any change from our end. Here are the steps I took:
While exchanging the code for a token after user authentication, I retrieved and saved Account.HomeAccountId.Identifier, Account.HomeAccountId.ObjectId and TenantId for the account.
I implemented my own version of IAccount.
Instead of calling await app.GetAccountAsync(accountID), I used my implementation of IAccountand initialized it with the data I saved in Step 1.
I used this account to call app.AcquireTokenSilent(microsoftScopes, account).
And that's it! No error was thrown once this was done!

Discord.js unable to login after using Client#destroy()

switch (command[0])
{
case 'restart':
if(msg.author.id == config["owner"]){
msg.channel.send(preEmbed('clientRestart'));
client.destroy();
client.login(config["token"]);
}
break;
}
this causes the error DiscordjsError: Request to use token, but token was unavailable to the client.
anyone know the cause / fix?
According to discord.js' github repo, you get that message when you don't provide a token, so make sure you are providing the token correctly.

iOS Facebook SDK 4.x read and publish permissions redundant logging in

I am upgrading the Facebook sdk from 3.x to 4.x and the Facebook docs make it clear that read permissions and publish permissions need to be requested separately. When the app requests read permissions, the user logs in and grants the permissions but when the app requests publish permissions, it makes the user log in again even though the user already has an access token? Is there a way to just request the permissions without having to force the user to log in again?
The Facebook android sdk allows this without having to log in twice but iOS seems to be preventing this behavior completely, which seems crazy. If an app implementation requires both read and publish permissions for the integration to even work, forcing the user to log in twice is just unnecessary friction and a bad user experience.
I have gone through the SDK class named FBSDKInternalUtility.h, in which we got one method
+ (BOOL)areAllPermissionsReadPermissions:(NSSet *)permissions
{
for (NSString *permission in permissions) {
if ([[self class] isPublishPermission:permission]) {
return NO;
}
}
return YES;
}
+ (BOOL)isPublishPermission:(NSString *)permission
{
return [permission hasPrefix:#"publish"] ||
[permission hasPrefix:#"manage"] ||
[permission isEqualToString:#"ads_management"] ||
[permission isEqualToString:#"create_event"] ||
[permission isEqualToString:#"rsvp_event"];
}
They check below permission in both cases which, while passing permission as NSSet order are getting different, so below checks for first string and return NO. So What did is I have commented out few lines as mentioned below.
+ (BOOL)areAllPermissionsReadPermissions:(NSSet *)permissions
{
//for (NSString *permission in permissions) {
// if ([[self class] isPublishPermission:permission]) {
// return NO;
// }
//}
return YES;
}
I not sure about the changes what I have done is valid or not, but I could have achieved what I wanted. So Happy.
Please, let me know if you have any suggestion to change.

How to delete a video from youtube using youtube v3 api and C#

Well I am able to upload video on Youtube but i didn't find a way or relevant code to delete video/videos from Youtube.
Here is my code which i tried to delete the youtube video.
private async Task Run()
{
UserCredential credential;
using (var stream = new FileStream("client_secret.json", FileMode.Open, FileAccess.Read))
{
credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
new[] { YouTubeService.Scope.Youtube },
"user",
CancellationToken.None
);
}
var youtubeService = new YouTubeService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = Assembly.GetExecutingAssembly().GetName().Name
});
var videosDeleteRequest = youtubeService.Videos.Delete("Video ID");
await videosDeleteRequest.ExecuteAsync();
}
But getting 403 response
Error: Google.Apis.Requests.RequestError
Insufficient Permission [403]
Errors [
Message[Insufficient Permission] Location[ - ] Reason[insufficientPermis
sions] Domain[global]
]
A little help or any possible solution will be highly appreciable.
The error translates to:
The video that you are trying to delete cannot be deleted. The request
might not be properly authorized.
https://developers.google.com/youtube/v3/docs/videos/delete
Have you successfully acquired the token of the user that owns the video?
The videos.delete method is preformed on private user data. In order to delete the data you must have permission or consent of the user to access their account. They must have granted you permission in one of the following scopes.
The error message
Message[Insufficient Permission] Location[ - ] Reason[insufficientPermis
sions] Domain[global]
Means that the user did not grant you permission with a hig enough scope. If for example you asked for authorization with only a read only scope you would then not have enough permissions to delete a video.
However if we check your code we can see that you are in fact using YouTubeService.Scope.Youtube. However if you have previously run your application then the client library stored the consent of the user. If you then have changed the scope and not forced the user to consent to authorization again. Then you are still running on the old consent.
The solution in this case is to change "user" to something else which will force it to request authorization again.

Publishing Check-in via Facebook IOS SDK

I'm trying to publish a check-in on a users wall. I don't need to get the longitude and latitude of the users device. But rather have this static as well as the place the user will check-in too. Basically a "check-in" button that already has static coordinates and a message.
I got the demo app up and running but can't seem to find any step by step tutorials on this particular topic. Is there any link around or a sample project you can point me to?
Thanks!
First, you need to have a place id. Assuming you have that you can use the Facebook Graph API to make a feed post to check-in the user.
You can do something like this (using Facebook iOS SDK 3.0):
[FBRequestConnection startForPostStatusUpdate:#"Awesome place!"
place:#"110506962309835"
tags:nil
completionHandler:^(FBRequestConnection *connection,
id result,
NSError *error) {
//verify result
}
];
Or:
[FBRequestConnection startWithGraphPath:#"me/feed"
parameters:#{#"place":#"110506962309835"}
HTTPMethod:#"POST"
completionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
//verify result
}];
You will need to ask the user for publish_stream permission before making this call.

Resources