Linkedin ios sdk returns wrong data - ios

I have integrated linkedin ios sdk in my ios app. So when I click on button to authenticate with linkedin a viewcontroller is shown and page to enter username and password is shown. Now when I enter the correct username and password it returns a url with code and state in it. The problem is that the state(which is a random string) which was send with the request is not the same that is received in response url. For example if I send
state = #"qwertyu"
Then the return value is
state = #"qwertyu#!"
An extra #! is appended with it.
In the code I am checking if the send and received state are same as it is not same I am returning an error(This is the error which it shows after entering correct username and password). If I remove that if condition then it is working perfectly fine.
SYLinkedInApplication *app = [SYLinkedInApplication
applicationWithRedirectURL:self.redirectUrl
clientId:self.appKey
clientSecret:self.appSecret
state:#"<RANDOM-STRING>"
grantedAccess:#[#something];
The condition
if ([self.application.state isEqualToString:receivedState]) {
//if true send success
}
So my question is
1) Do we need the if condition for checking the state?
2) If we need the condition then why is the return state string different?
Hope the question is clear.
Thanks in advance.

I solved the problem (but with Ionic).
1) Yes you should check for the state, to prevent CSRF.
2) That's the problem I solved by changing the URL when requesting authorization and access token:
From https://www.linkedin.com/uas/oauth2/authorization to https://www.linkedin.com/oauth/v2/authorization
And https://www.linkedin.com/uas/oauth2/accessToken to https://www.linkedin.com/oauth/v2/accessToken
That solved my problem. I hope it solves yours too, or someone else's.

Related

Google OAuth 2 access token not working as expected some hours after authorizing

I'm using the Google Identity Platform's OAuth 2.0 flow to authorize a javascript/HTML teacher observation form to write to a Google Sheets document. Everything is working well most of the time; however, last night one of our principals hit the following error:
"Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project."
I determined that he had launched the observation tool in the afternoon, and now maybe five hours later was trying to click the submit button. My hunch was that the token had expired, but from Google's documentation it seems like the JS auth library is meant to handle refreshing the access token as necessary - I believe it's not actually possible to get a refresh token to do anything manually.
I'm using what is essentially the sample auth code, and the app responds to being signed out appropriately. That is, if I sign out in another tab, the submit button is disabled and the sign-in button appears again. Assuming token expiration is the issue here, any ideas on the correct way to identify if the token has expired and how to request a new one, ideally without user interaction? Or if it's not an expiration issue, what else could it be? This user has successfully submitted data in earlier observations; it was just this one time when he waited ~5 hours (potentially losing internet connectivity / sleeping his laptop) during that time.
Here's the auth code:
var clientId = ""; //id removed
var discoveryDocs = ["https://sheets.googleapis.com/$discovery/rest?version=v4"];
var scopes = "https://www.googleapis.com/auth/spreadsheets";
var authorizeButton = document.getElementById('authorize-button');
function handleClientLoad() {
gapi.load('client:auth2', initClient);
}
function initClient() {
gapi.client.init({
discoveryDocs: discoveryDocs,
clientId: clientId,
scope: scopes
}).then(function () {
gapi.auth2.getAuthInstance().isSignedIn.listen(updateSigninStatus);
updateSigninStatus(gapi.auth2.getAuthInstance().isSignedIn.get());
authorizeButton.onclick = handleAuthClick;
});
}
function updateSigninStatus(isSignedIn) {
if (isSignedIn) {
authorizeButton.style.display = 'none';
document.getElementById('submit').disabled = false;
findRow(); //find the empty row once we're logged in
} else {
authorizeButton.style.display = 'block';
document.getElementById('submit').disabled = true;
}
}
function handleAuthClick(event) {
gapi.auth2.getAuthInstance().signIn();
}
Thank you!
Similar issues that i had resulted in issues from that Authorized Javascript origins.
"In the Authorized JavaScript origins field, enter the origin for your app. You can enter multiple origins to allow for your app to run on different protocols, domains, or subdomains. You cannot use wildcards. In the example below, the second URL could be a production URL." taken from https://developers.google.com/identity/sign-in/web/devconsole-project.If prompt to view task came from an email, the email origin must be verified -or- the device is used for multiple accounts, the token will not stay. If the api is being improperly used, it will allow functionality for a short period of time , then fail.
This may be useful, in the authflow, you do not have scope or id in options
/** * Initiate auth flow in response to user clicking authorize button. * *
#param {Event} event Button click event. */ function
handleAuthClick(event) {
gapi.auth.authorize( {client_id: '[#app:client_id]', scope:
["googleapis.com/auth/calendar"], immediate: false}, handleAuthResult);
return false; }
I believe How to refresh expired google sign-in logins? had the answer I needed. Since all of my API calls happen at once, I added a new Date() when the page loads, a second new Date() when the submission flow begins, and if they are more than 45min (2,700,700ms) apart, I use gapi.auth2.getAuthInstance().currentUser.get().reloadAuthResponse() to force an access token refresh, as documented at https://developers.google.com/identity/sign-in/web/reference#googleuserreloadauthresponse.
Hopefully Google will eventually update their documentation to reflect this now-necessary step when using the auth2 flow vs the older auth flow.
Time will tell if this actually solved the issue, but I'm hopeful!
I hope it helps you friend that error is because you have the wrong time, you go to date and time settings then press synchronize now.

How to detect that the current request is an authentication callback?

I have a single-page JavaScript application and I'm using the Auth0 service for signup/login.
I have integrated the Lock widget and I'm saving a string to localStorage after a user is authenticated, like so:
lock.on("authenticated", function(authResult)
{
localStorage.setItem('login', authResult.idToken);
}
The problem is that when Auth0 redirects them back to my application after logging in, the authenticated event is fired only after page loaded, but by that time, I've already done the check to see if the localStorage string is set (which it is not); therefore, the user just keeps getting asked to login again:
if(localStorage.getItem('login') == undefined)
{
lock.show(function(err, profile, token)
{
// ...
}
}
I tried to see if there was anything special passed in to the page after a callback - but the referrer isn't always there.
If I don't automatically prompt the user to login, but instead show a login button - the authenticated event never fires for some reason.
How do I get around this?
Based on the information provided you seem to be using Lock in redirect mode and if that's the case you can use the hash_parsed event as a way to know if Lock found a response that it will process.
Every time a new Auth0Lock object is initialized in redirect mode (the default), it will attempt to parse the hash part of the URL, looking for the result of a login attempt. After that, this event will be emitted with null if it couldn't find anything in the hash. It will be emitted with the same argument as the authenticated event after a successful login or with the same argument as authorization_error if something went wrong.
Leveraging this event you could do the following:
Subscribe to the hash_parsed event:
If hash_parsed is emitted with null and localStorage has no indication the user already logged in then redirect to login.
If hash_parsed is emitted with a non-null value that either the authenticated or authorization_error will be emitted and you can react accordingly.
Some sample code:
lock.on("hash_parsed", function (response) {
if (!response && !localStorage.getItem('login')) {
// Redirect to the login screen
} else {
// Either the user is already logged in or an authentication
// response will be processed by Lock so don't trigger
// an automatic redirect to login screen
}
});

How to force Google OAuth popup in Firebase when user already authenticated previously?

Whenever a user has previously authenticated with Google, it automatically defaults to logging them in with THAT account on subsequent attempts. I want to eliminate this and force the popup/redirect so that a user with multiple google accounts can choose which one to use. How?
Background:
The automatic logging in feature is proving problematic for me as I have a whitelisted set of e-mails for users allowed to use my app. If a Google user chooses the wrong account when first logging in, they can't go back and choose the one associated to their whitelisted e-mail.
Just as #nvnagr said, you can do this with the following code:
var provider = new firebase.auth.GoogleAuthProvider();
provider.setCustomParameters({
'prompt': 'select_account'
});
But I think you need to update the firebase version to 3.6.0 something.
Google supports a parameter in authentication url to deal with this issue.
If you add prompt=select_account in your request to Google authentication, it'll force the user to do an account selection. See the details and other values of prompt.
https://developers.google.com/identity/protocols/OpenIDConnect#authenticationuriparameters
I'm not sure if there is an easy way to add this parameter through firebase api.
When you're calling the oAuth function, you can pass a third options parameter to make the authentication last for the session only. This should solve your problem. Docs
var ref = new Firebase("https://<YOUR-FIREBASE-APP>.firebaseio.com");
ref.authWithOAuthPopup("google", function(error, authData) {
if (error) {
console.log("Login Failed!", error);
} else {
console.log("Authenticated successfully with payload:", authData);
}
}, {
remember: 'sessionOnly'
});

Unable to Logout of Facebook within Unity IOS [duplicate]

I've managed to successfully log in FB using FB.Login function. Now I want to log out:
FB.Logout();
Debug.Log("FB IS LOGGED IN " + FB.IsLoggedIn);
I am expecting the above code to print the value of FB.IsLoggedIn as false and to ask me for a login and password on the next FB.Login.
In fact the value of FB.IsLoggedIn is true and I am not being logged out: next call to FB.Login does not ask for password and I am not being logged out when I open facebook site in my browser.
I've also tried to use the undocumented request to https://www.facebook.com/logout.php?next=[YourAppURL]&access_token=[ValidAccessToken] but it didn't make any effect for me.
How can I log the user out of facebook in my standalone unity application?
In fact what I need is to log in with different login and password.
Maybe I can invalidate the access token somehow which will cause the FB to ask me for login and password again?
Any help is much appreciated.
SDK version: 5.0.1
Build version: 140401.725cc2ecbc9002a
Unity Version 4.3.3f1 (c8ca9b6b9936)
I believe the FB.Logout operation is asynchronous, and the value of FB.IsLoggedIn would be true immediately after calling FB.Logout(). If you look at the documentation, it says:
You almost certainly should not use this function, which is provided
primarily for completeness. Having a logout control inside a game that
executes a Facebook-wide logout will violate users' expectations.
Instead, allow users to control their logged-in status on Facebook
itself.
Actually FB.Logout() has no delegate to let you know that account is successfully logout, so you have to create your own listner.
Secondly it will not sign you out from the actual device Facebook app or browser.
If you want to sign in with different account, so you can do by signing out explicitly from the app or browser.
Here is the code for how to detect that if you are logged out. It may useful to show Login and Logout button for Facebook that when to Login or Logout.
Here is the code from that you can determine the user has logged out within the Game.
public void OnFacebookLogout()
{
if (FB.IsLoggedIn)
{
FB.Logout ();
StartCoroutine ("CheckForSuccussfulLogout");
}
}
IEnumerator CheckForSuccussfulLogout()
{
if (FB.IsLoggedIn)
{
yield return new WaitForSeconds (0.1f);
StartCoroutine ("CheckForSuccussfulLogout");
} else
{
// Here you have successfully logged out.
// Do whatever you want as I do, I just enabled Login Button and Disabled
// logout button through this method.
EnableFacebookLoginButton ();
}
}
I'm not sure if it is correct but why not just do some while loop?
IEnumerator FBLogout (){
FB.Logout ();
while (FB.IsLoggedIn){
print ("Logging Out");
yield return null;
}
print ("Logout Successful");
}

iOS OneDrive (skydrive) app displays permissions dialog every time it runs

I'm developing an iOS app that gives users access to their OneDrive/SkyDrive and I've run into a very annoying issue:
The very first time a user links the app to their OneDrive, everything goes as expected:
They have to enter a user id and password
Then they have to agree to let the app access their info
Then they get to browse their OneDrive
That's all good.
But, if the app closes, and you try to access the OneDrive again, rather than skipping straight to #3, and being able to access the OneDrive, they are stopped at step #2 (step 1 is skipped, as expected) and they have to agree again to let the app access their info.
The code is taken directly from the iOS examples in the online documentation (with some slight modification based on samples found here on Stack Overflow), but, here it is for inspection:
- (void) onedriveInitWithDelegate:(id)theDelegate {
self.onedriveClient = [[LiveConnectClient alloc] initWithClientId:MY_CLIENT_ID
delegate:theDelegate
userState:#"initialize"];
}
And then, theDelegate implements this:
- (void)authCompleted:(LiveConnectSessionStatus) status
session:(LiveConnectSession *) session
userState:(id) userState {
NSLog(#"Status: %u", status);
if ([userState isEqual:#"initialize"]) {
NSLog( #"authCompleted - Initialized.");
if (session == nil) {
[self.onedriveClient login:self
scopes:[NSArray arrayWithObjects:#"wl.basic", #"wl.signin", #"wl.skydrive_update", nil]
delegate:self
userState:#"signin"];
}
}
if ([userState isEqual:#"signin"]) {
if (session != nil) {
NSLog( #"authCompleted - Signed in.");
}
}
}
I thought that perhaps the status value might give a clue and that maybe I could avoid the login call, but it's always zero/undefined when I get to authCompleted after calling initWithClientId. (And session is always nil.)
Is there a scope I'm missing? Is there a different call to make rather than a straight-up login call? Or is it more complicated than that? I've seen reference to "refresh tokens" related to OAuth2 login, but I've not been able to find any concrete examples of how they might be used in this situation.
Any help and/or insights greatly appreciated.
Diz
Well, it turns out that the answer is pretty simple here. I just needed to add the "wl.offline_access" scope to my list of scopes during the initial login operation. The docs didn't really imply this type of behavior for this scope, but, that did the trick for me.
With this new scope added, subsequent invocations of the app no longer bring up the "agree to give the app these permissions" dialog, and I can go straight to browsing the OneDrive.
(Credit where it's due: Stephane Cavin over at the microsoft forums gave me the tip I needed to work this out. Gory details are here:
http://social.msdn.microsoft.com/Forums/en-US/8c5c7a99-7e49-401d-8616-d568eea3cef1/ios-onedrive-skydrive-app-displays-permissions-dialog-every-time-it-runs?forum=onedriveapi )
Diz

Resources