When a user connects to my SoundCloud web app and then disconnects it through their SoundCloud settings, my app stops working and returns a 401 error:
Error Code 500
The requested URL responded with HTTP code 401.
I'm using the SoundCloud PHP library.
Currently on connecting I save the user's Soundcloud User ID to a session and database, and I save the oauth token and secret to a database.
What happens is when the user hits Connect on my website after disconnecting the app from their SoundCloud settings is the following:
Code checks the user's SoundCloud ID and tries to authenticate using the OAuth credentials saved to the database.
Since the user disconnected from the app, the OAuth credentials no longer work and returns an access denied error.
I'm looking for a way to detect this error and remove the database entry containing the no longer working OAuth token in order to allow the user to properly reconnect.
I tried with the following code:
$result = User::model()->findByAttributes(array("oauth_uid"=>$_SESSION['scid']));
//If result is empty create login URL
if(empty($result)){
$sc_auth = false;
$scloginurl = $client->getAuthorizeUrl(array("scope"=>"non-expiring"));
//Else if result is found, try setting the access token, if access token returns errors get login URL
}else{
try{
$client->setAccessToken($result['oauth_token']);
} catch (Services_Soundcloud_Invalid_Http_Response_Code_Exception $e){
$scloginurl = $client->getAuthorizeUrl(array("scope"=>"non-expiring"));
$sc_auth = false;
$error = 1;
}
As you can see above, I tried using 'try() catch()' to see if there's any errors from setting the access token, however the website seems to return the same error and not execute any of the code in catch().
Solved it by going into the SoundCloud.php file from SoundCloud's PHP Library and replacing the code of
throw new Services_Soundcloud_Invalid_Http_Response_Code_Exception( .... );
with my code to remove the database entry and reload the window!
A little wonky since it will remove the entry regardless of exception, but it works!
Related
In a deprecation announcement from Google, they say that developers need to migrate away from these scopes:
https://www.googleapis.com/auth/userinfo.email
https://www.googleapis.com/auth/userinfo.profile
and instead use these scopes:
email
profile
After doing so on my App-Engine backend, however, I'm having problems with my iOS app. On first run, it asks me to sign in and the screen shows both scopes correctly after which the app runs just fine. On the second run, where it is supposed to retrieve the authorization credentials from protected storage, it does not work as the App-Engine server is receiving null for the User parameter in the endpoint.
The App-Engine endpoint requires both the email and profile scope. The iOS code for retrieving previous credentials is:
GTMOAuth2Authentication* auth =
[GTMOAuth2ViewControllerTouch authForGoogleFromKeychainForName:AUTH_KEYCHAIN_NAME
clientID:Constants.IOS_CLIENT_ID
clientSecret:Constants.IOS_CLIENT_SECRET];
and the iOS code for authenticating should there be no previous credentials is:
viewController = [[GTMOAuth2ViewControllerTouch alloc]
initWithScope:Constants.EMAIL_SCOPE
clientID:Constants.IOS_CLIENT_ID
clientSecret:Constants.IOS_CLIENT_SECRET
keychainItemName:AUTH_KEYCHAIN_NAME
delegate:self
finishedSelector:#selector(viewController:finishedWithAuth:error:)];
This used to work just fine! Now the App-Engine server changed the email scope from .../userinfo.email to email and the profile scope from .../userinfo.profile to profile. The iPad app exhibits the same behavior against the new backend with Constants.EMAIL_SCOPE set to either value.
The google-api-objectivec-client library is v0510, the latest.
The Android version of my app continues to work just fine without any code changes after the backend change.
Update 2015-02-26: Now using r424 (2014-12-30) of google-api-objectivec-client. No change. If the AppEngine backend is using the new "profile" and "email" scopes, the iOS app cannot authenticate on the second (or later) run where it is loading the credentials from store rather than going through the sign-in flow.
The AppEngine log of the first (sign-in credentials) shows:
com.google.api.server.spi.auth.GoogleIdTokenUtils getCurrentUser: getCurrentUser: IdToken; email=testuser#gmail.com
The AppEngine log of the second (loaded credentials) shows:
com.google.api.server.spi.auth.AppEngineAuthUtils getCurrentUser: getCurrentUser: AccessToken; Tried and failed to get client id for scope 'com.google.api.server.spi.config.scope.DisjunctAuthScopeExpression#a015b54e'
com.google.appengine.api.oauth.InvalidOAuthParametersException:
at com.google.appengine.api.oauth.OAuthServiceImpl.makeSyncCall(OAuthServiceImpl.java:139)
at com.google.appengine.api.oauth.OAuthServiceImpl.getGetOAuthUserResponse(OAuthServiceImpl.java:118)
at com.google.appengine.api.oauth.OAuthServiceImpl.getAuthorizedScopes(OAuthServiceImpl.java:90)
at com.google.api.server.spi.auth.AppEngineAuthUtils.getOAuth2AuthorizedScopes(AppEngineAuthUtils.java:140)
at com.google.api.server.spi.auth.AppEngineAuthUtils.getCurrentUser(AppEngineAuthUtils.java:89)
...
This exception does not propagate up; null is returned for the user.
Is there something else that needs to be done for the GTMOAuth2ViewControllerTouch to work correctly with the new scopes? Or is there perhaps something wrong on the AppEngine side?
I'm trying to write an app that can tweet using an 'application' I registered with Twitter. I am using TweetSharp and have tried to get my TwitterService set up as follows:
public Twitter(string consumerKey, string consumerSecret)
{
this.twitterService = new TwitterService(consumerKey, consumerSecret);
OAuthRequestToken oAuthRequestToken = this.twitterService.GetRequestToken();
Uri uri = this.twitterService.GetAuthorizationUri(oAuthRequestToken);
Process.Start(uri.ToString());
OAuthAccessToken oAuthAccessToken =
this.twitterService.GetAccessToken(oAuthRequestToken);
this.twitterService
.AuthenticateWith(oAuthAccessToken.Token, oAuthAccessToken.TokenSecret);
}
It gets to the OAuthAccessToken line and then takes me to the Authorize [my app] to use your account? page on the Twitter website. Before I specified a phony callback url, it displayed a page with the PIN that my user is supposed to enter when I clicked the 'Authorize app' button. Then when I added a phony callback url, it would attempt to go to that page and my code would blow to smithereens with the following error:
The remote server returned an error: (401) Unauthorized.
What I want to know is: can I tweet programatically without the need to enter a PIN or have a legitimate callback url?
Tweets must be sent in the context of a user. (Ref: POST statuses/update.) Therefore, your app must get the user's authorization (an OAuth access token) in order to send a Tweet. Since you can't get an access token without using either PIN-based authentication or a callback URL, I'm afraid that what you are asking simply cannot be done.
If, however, you just want to avoid prompting your users to enter the PIN each time they start your app, then the answer is simple: Once you have a valid access token, save it somewhere (e.g. to a file) and then reload it next time your app runs. For my WinForms app, I use .NET's built-in per-user Settings mechanism to store the Access Token and Access Token Secret. A web app would probably be better off using a database or similar to persist access tokens.
Note: If you do this, you'll also need to check the validity of the stored access token, and repeat the authorization process if it's no longer valid. The Twitter API documentation suggests using the GET account/verify_credentials method for this purpose.
I'm trying to log a conversion pixel with Facebook SDK iOS 3.2 by calling
[FBInsights logConversionPixel:<pixelID> valueOfPixel:0]
Now...
I'm doing this before I know the user logged in with facebook, so it's not certain I have an active FBSession with a user access token to this app.
In result I get the following error:
{
code = 100;
message = "(#100) Graph API for app id <appID> called, but token has app id 0";
type = OAuthException;
}
If the user logs in to facebook and then log the conversion, everything works fine.
The thing I don't get is why do a logging of a conversion pixel needs to happen from an authorized session, in the php code of the app I can simply go to https://www.facebook.com/offsite_event.php?id=<pixelID>&value=0 without any access token and it will mark my conversion pixel.
Any thoughts/ideas of how can use FBInsights without an active session?
If this problem still actual (maybe will actual for someone), then you can try set Client token for FBSettings class
[FBSettings setClientToken:#"<your app client token>"];
You can get client token on your app settings page - Advanced - Security section. There should be checkpoint "Client token" that set to OFF. Just set it ON and save changes, then you get client token
THE PROBLEM
I was able to connect to Twitter the the HybridAuth library, and it stopped working. Posting to a Twitter account was also functional.
WHAT I HAVE TRIED
Resetting my Twitter app access tokens.
Creating an All new Twitter app.
Using the HybridAuth debug mode to troubleshoot.
THE ERROR MESSAGE
"Authentification failed. The user has canceled the authentication or the provider refused the connection.
Original error message: Authentification failed! Twitter returned an error. 401 Unauthorized."
MY RESEARCH
This seems to be attributed to the lack of the key and secret, but I set these in the Twitter config file.
THE CODE
$hybridauth = new Hybrid_Auth( $config );
$adapter = $hybridauth->authenticate( "Twitter" );
$hybridauth_session_data = $hybridauth->getSessionData();
store_session_data($hybridauth_session_data);
// get the user profile
$user_profile = $adapter->getUserProfile();
The exception is being thrown by the authenticate method. Before it would ask me to allow access via the app and now it throws the error.
If you need more information, please let me know.
Rick
So HERE's what happened and what you should know:
Twitter keeps track of the current time
If an API request to authenticate comes from a server that claims it is a time that is outside of 15 minutes of Twitter time, it will fail with a 401 error.
HOW I fixed it:
I set my server time to the correct time by using the USNO Master Clock. It happened to be just over 15 minutes offset.
This is just another solution which was my case:
Set the "Callback URL" in the Twitter App(If you are testing in local, you can use an example URL).
They didn't specify this as a mandatory field and they allow overriding this URL with the one in the HybridAuth request.
in case somebody else cant edit their server time too, there is a workaround for that. The most basic and probably not the cleanest way is just going to Hybrid/thirdparty/OAuth/OAuth.php locating generate_timestamp() function and adding what ever the time discprenecy there is between your server and gtm+0 to the time(). like this:
private static function generate_timestamp() {
return time() + 7200;
}
in my case, my server is gtm-2, so I had to add 2 hours (in seconds) to the time() function in order to make it work.
The website I'm making makes it possible to connect your account with your youtube account. From localhost, this works perfectly, but from the site, which is step1tuts.appspot.com, it doesn't work. When I redirect the user to the authentication page from my website, I get the following message:
The page you have requested cannot be displayed. Another site was
requesting access to your Google Account, but sent a malformed
request. Please contact the site that you were trying to use when you
received this message to inform them of the error.
The code that handles this authentication looks like this:
client = youtube.get_client()
client.developer_key = 'AI39si759T7YcZ4E3XvICpZr3cGwQ0Ev4AjwyJrVSS6AW6NUc7_t10DX1JsngWzU4YoGjpsjAUTejav0hgXp9vDuM7a83tDXzQ'
client.client_id = 'step1tuts.com'
domain = 'http://' + os.environ['HTTP_HOST']+"/user/youtube_token"
scope = 'http://gdata.youtube.com'
url = client.GenerateAuthSubURL(domain,scope,secure=False,session=True)
self.redirect(str(url))
return
The url I'm redirecting to, ending in /auth_token then processes the token it gets back from youtube, but the error happens here.
Just for clarity, the youtube.get_client method is one that I developed to reuse the process of making the client appengine ready: the code for that is:
def get_client():
client = gdata.youtube.service.YouTubeService()
run_on_appengine(client)
client.developer_key = 'AI39si759T7YcZ4E3XvICpZr3cGwQ0Ev4AjwyJrVSS6AW6NUc7_t10DX1JsngWzU4YoGjpsjAUTejav0hgXp9vDuM7a83tDXzQ'
client.client_id = 'step1tuts.com'
user = users.get_current_user()
if(user and user.yt_token):
client.SetAuthSubToken(user.yt_token)
return client
While pasting in this code, I noticed that I'm duplicating the part where I give my developer key. I don't think that that's the problem, but I'll remove that from the authentication part of my code, and see what happens.
The problem must be tracable by watching the url that the user is redirected to, so just for some extra info, the url that I'm redirected to when I'm using the app on my local machine using the SDK, with which it works:
http://www.youtube.com/auth_sub_request?scope=http%3A%2F%2Fgdata.youtube.com&session=1&next=http%3A%2F%2Flocalhost%3A8081%2Fuser%2Fyoutube_token%3Fauth_sub_scopes%3Dhttp%253A%252F%252Fgdata.youtube.com&secure=0&hd=default
And the url that I'm redirected to when I use the same code on production:
http://www.youtube.com/auth_sub_request?scope=http%3A%2F%2Fgdata.youtube.com&session=1&next=http%3A%2F%2Fstep1tuts.appspot.com%2Fuser%2Fyoutube_token%3Fauth_sub_scopes%3Dhttp%253A%252F%252Fgdata.youtube.com&secure=0&hd=default
Interesting. All other urls work except this one. Probably a bug on youtube side? I just added a '.' at the end of your domain and the request seems to go through. Maybe you can try that?
http://www.youtube.com/auth_sub_request?scope=http%3A%2F%2Fgdata.youtube.com&session=1&next=http%3A%2F%2Fstep1tuts.appspot.com.%2Fuser%2Fyoutube_token%3Fauth_sub_scopes%3Dhttp%253A%252F%252Fgdata.youtube.com&secure=0&hd=default