OAuth "Invalid verification code format" - ruby-on-rails

I've got a production app and occasionally I see this error appear in the logs.. I can't seem to duplicate it on my end, so it seems like there is a user out there somewhere with some specific settings / cookies / etc that are causing this problem. I am not sure... The log shows that this user was redirected to this callback url: "users/auth/facebook/callback?code=AQCayaAoFOruFgwbfg1D682j8DbxOt0CZYNH3Vv5RtYKlQgSzISyN8ygTn25W_RTl3fu35cS1-tl5ArZ9B_XylwORP0hGU6st8P6TyTYUzfiR1m0poaSRkX-KBeWiBvT6IUsm-Af0VJcUNTQPg-dM1F9y5CgJ2bTJEJqhCE9wYlvkUY3kguwcl3TQ48FTT4-PhA///"
The actual error is:
RuntimeError: #<OAuth2::Response:0x1da7fae0 #error=#<OAuth2::Error: OAuth2::Error>, #options={:parse=>:query}, #parsed={"{\"error\":{\"message\":\"Invalid verification code format.\",\"type\":\"OAuthException\"}}"=>nil}, #response=#<Faraday::Response:0x1da8fa80 #on_complete_callbacks=[], #env={:response=>#<Faraday::Response:0x1da8fa80 ...>, :request_headers=>{"Content-Type"=>"application/x-www-form-urlencoded"}, :body=>"{\"error\":{\"message\":\"Invalid verification code format.\",\"type\":\"OAuthException\"}}", :status=>400, :url=>#<Addressable::URI:0xed52bf0 URI:https://graph.facebook.com/oauth/access_token>, :request=>{:proxy=>nil}, :parallel_manager=>nil, :response_headers=>{"expires"=>"Sat, 01 Jan 2000 00:00:00 GMT", "access-control-allow-origin"=>"*", "content-type"=>"text/javascript; charset=UTF-8", "connection"=>"close", "www-authenticate"=>"OAuth \"Facebook Platform\" \"invalid_code\" \"Invalid verification code format.\"", "date"=>"Thu, 13 Oct 2011 15:58:29 GMT", "content-length"=>"81", "cache-control"=>"no-store", "x-fb-rev"=>"457598", "x-fb-server"=>"10.65.13.60", "pragma"=>"no-cache"}, :ssl=>{:ca_file=>"/etc/pki/tls/certs/ca-bundle.crt"}, :method=>:post}>>
and the parameters were:
{"code"=> "AQCayaAoFOruFgwbfg1D682j8DbxOt0CZYNH3Vv5RtYKlQgSzISyN8ygTn25W_RTl3fu35cS1-tl5ArZ9B_XylwORP0hGU6st8P6TyTYUzfiR1m0poaSRkX-KBeWiBvT6IUsm-Af0VJcUNTQPg-dM1F9y5CgJ2bTJEJqhCE9wYlvkUY3kguwcl3TQ48FTT4-PhA///",
"action"=>"",
"controller"=>""}
I know if I manually go to "users/auth/facebook/callback?code=blah" it will trigger this same error because the callback code parameter is obviously bogus, but it doesn't look like there's anything suspicious about the actual code in the user's params hash-- so I am wondering why it would be an invalid format?
Has anyone else experienced this?

I think the following link provides the answer: http://developers.facebook.com/docs/authentication/#authenticating-users-in-a-web-application
You first need to call https://graph.facebook.com/oauth/authorize with your client_id and redirect_uri. This will then redirect you back to the redirect_uri, with a verification code in the query string that you can pass to your https://graph.facebook.com/oauth/access_token call (via the code parameter) to exchange for an oAuth access token.
Good luck! :)

Related

How to detect when an OAuth2 refresh-token expired

When accessing Google-Drive, an access-token can expire and we can use the refresh-token to get a new access-token. There are a number of possible reasons though, that the refresh-token itself stops working or expires, see:
https://developers.google.com/identity/protocols/OAuth2#expiration
So my question, what happens if the refresh-token has expired after the 6 months, how can I detect it? Does the request for refreshing the access-token fail with 403 forbidden, or does it return a JSON containing an error message, or something else?
Unfortunately it is hard to find any information about this, and to test it out one has to wait for 6 month...
Solution:
Thanks to Gary Archers answer I could produce the situation with an invalid refresh-token and this is the response I got, maybe it helps somebody else:
HTTP-status-code: 400
JSON:
{
"error": "invalid_grant",
"error_description": "Bad Request"
}
Almost all implementations I've seen return a known error code of 'invalid_grant' that you can check for. It will look something like this, with the server returning a JSON response with an error field and an optional error_description. At this point you need to redirect the user to reauthenticate:

Amazon MWS Products API returns 401 error "Access denied"

I'm hopelessly stuck on trying to call Amazon MWS Products API. Particularly I'm trying to request this function
It requires building a pretty complicated request with a signature:
POST /Products/2011-10-01 HTTP/1.1
Content-Type: x-www-form-urlencoded
Host: mws.amazonservices.com
User-Agent: <Your User Agent Header>
AWSAccessKeyId=AKIAEXAMPLEFWR4TJ7ZQ
&Action=ListMatchingProducts
&MWSAuthToken=amzn.mws.4ea38b7b-f563-7709-4bae-87aeaEXAMPLE
&MarketplaceId=ATVPDKIKX0DER
&Query=0439708184
&SellerId=A1IMEXAMPLEWRC
&SignatureMethod=HmacSHA256
&SignatureVersion=2
&Timestamp=2012-12-12T22%3A23%3A50Z
&Version=2011-10-01
&Signature=V%2BEXAMPLERT%2Baj%2Fxwqo7y3PIifMFHeqFlNYW0EXAMPLEA%3D
I build this query with the help of this little library:
So my final url string looks like this:
https://mws.amazonservices.com/Products/2011-10-01?AWSAccessKeyId=<MY_ACCESS_KEY>&Action=ListMatchingProducts&MarketplaceId=A1PA6795UKMFR9&Query=0439708184&SellerId=<SELLER_ID>&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=2016-04-19T16%3A50%3A13Z&Version=2011-10-01&Signature=mZt3OhM14gwLdsQ%2Bhxz5UFMzr7m2U36DvZ7RG3dcsTI%3D
And it seems that the url string is built correctly. I think so because if a parameter is missing or incorrect the API returns 400 error with explanation that this parameter is invalid. The same applies for the signature. If signature is incorrect the API returns error which clearly states that the signature is invalid. So, again, I think that the url must be ok. However the API returns 401 error and a html page which looks like this:
<?xml version="1.0"?>
<ErrorResponse xmlns="http://mws.amazonservices.com/schema/Products/2011-10-01">
<Error>
<Type>Sender</Type>
<Code>AccessDenied</Code>
<Message>Access denied</Message>
</Error>
<RequestID>7b12e3c8-7b1a-4b6e-b7ba-15ec8c4e0968</RequestID>
</ErrorResponse>
Access denied. And I have no idea why. I've spent several hours already trying to figure out what's wrong. Can anyone help me?
The reason for the problem was that I was calling American url https://mws.amazonservices.com instead of European one https://mws-eu.amazonservices.com. It would be really nice if Amazon response gave more context about the error than simply Access denied

Google Drive API returning 403 when trying to download file - no information about error given

So, I have a ruby on rails project, I'm using the google-api gem and I'm trying to download a file from an account that I previously gave permission to my project to access and manage my google drive files. I have the refresh token and the access token and for some time, the download works fine. For some reason, after the access_token expires, even after I request a new one from the API using the refresh (which does work), the download request returns a 403 error with no information whatsoever about what 403 error it is.
First: why, after refreshing the access_token, am I still getting the 403 error?
Second: why is the response not returning any information about the error?
Fyi, if I go to my account, de-authorize the app and then authorize it again through my app, the download works fine again.
I really need help, since this kinda breaks my whole project if it doesn't work.
Edit: Tried again to see if the problem was still happening. I deleted my account yesterday, gave permission again to manage files and it worked until the access_token expired. After that it gives the 403 error message, even after using the refresh token to update the access one. Below is what I get from client.execute (with the client key and secret edited):
Response from Google API: #"16653014193614665626", "e"=>"download", "gd"=>"true"}, #headers={"User-Agent"=>"google-api-ruby-client/0.7.1 Linux/3.13.0-24-generic\n (gzip)", "Accept-Encoding"=>"gzip", "Content-Type"=>""}, #api_method=nil, #authenticated=nil, #authorization=#https://accounts.google.com/o/oauth2/auth>, #token_credential_uri=#https://accounts.google.com/o/oauth2/token>, #expiry=60, #extension_parameters={}, #additional_parameters={}, #client_id="***.apps.googleusercontent.com", #client_secret="***", #scope=["https://www.googleapis.com/auth/drive", "https://www.googleapis.com/auth/userinfo.email"], #access_token="***", #refresh_token="***">, #body="", #http_method=:get, #uri=#>, #response=# #request=# #request_headers={"User-Agent"=>"google-api-ruby-client/0.7.1 Linux/3.13.0-24-generic\n (gzip)", "Accept-Encoding"=>"gzip", "Content-Type"=>"", "Authorization"=>"Bearer *", "Cache-Control"=>"no-store"} #ssl=# #response_headers={"access-control-allow-origin"=>"*", "access-control-allow-credentials"=>"false", "access-control-allow-headers"=>"Accept, Accept-Language, Authorization, Cache-Control, Content-Disposition, Content-Encoding, Content-Language, Content-Length, Content-MD5, Content-Range, Content-Type, Date, GData-Version, Host, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since, Origin, OriginToken, Pragma, Range, Slug, Transfer-Encoding, X-ClientDetails, X-GData-Client, X-GData-Key, X-Goog-AuthUser, X-Goog-PageId, X-Goog-Encode-Response-If-Executable, X-Goog-Correlation-Id, X-Goog-Request-Info, X-Goog-Experiments, x-goog-iam-role, x-goog-iam-authorization-token, X-Goog-Spatula, X-Goog-Upload-Command, X-Goog-Upload-Content-Disposition, X-Goog-Upload-Content-Length, X-Goog-Upload-Content-Type, X-Goog-Upload-File-Name, X-Goog-Upload-Offset, X-Goog-Upload-Protocol, X-Goog-Visitor-Id, X-HTTP-Method-Override, X-JavaScript-User-Agent, X-Pan-Versionid, X-Origin, X-Referer, X-Upload-Content-Length, X-Upload-Content-Type, X-Use-HTTP-Status-Code-Override, X-YouTube-VVT, X-YouTube-Page-CL, X-YouTube-Page-Timestamp", "access-control-allow-methods"=>"GET,OPTIONS", "date"=>"Wed, 20 Aug 2014 13:13:22 GMT", "expires"=>"Wed, 20 Aug 2014 13:13:22 GMT", "cache-control"=>"private, max-age=0", "server"=>"UploadServer (\"Built on Aug 12 2014 13:30:28 (1407875428)\")", "content-length"=>"0", "content-type"=>"text/html; charset=UTF-8", "alternate-protocol"=>"443:quic", "connection"=>"close"} #status=403>>>
After analysing the response while looking for things to hide (like the access_token), is it possible that the "access-control-allow-methods" paramater having the date and expires date the same is the issue here?
It seems the downloadUrl is directly connected to the access token. By storing the downloadUrl with the first access to the file's metadata and using the same downloadUrl with a new access token, the API was returning a 403 error. By requesting a new downloadUrl everytime a new token is requested as well, it works perfectly.
The 403 error means that you don't have the required rights, in this case, you are trying to use an expired token, this sounds like you have a problem with your cookie policy, change your cookie policy to none and let us know if the problem goes away.
Happy coding

Rails - post form with ajax request

I have some ajax that is POSTing data to a URL, and I can see Chrome sending off the data :
Request URL:http://ubuntu:3000/groups?authenticity_token=EjAsrE07jziAMLt918Mgid4PSpRFfjIaz%2Bd9ZCxmbTo%3D
Request Payload
{"object":{"name":"test","description":"testing","is_era":false,"unique_ui_identifier":"db3772f13e8c5ec958105c72f11b7b89"}}
I then look at the dev logs, and the server shows the following:
Started POST "/groups?authenticity_token=EjAsrE07jziAMLt918Mgid4PSpRFfjIaz%2Bd9ZCxmbTo%3D" for 192.168.222.1 at Mon Aug 26 10:46:19 +0930 2013
Processing by GroupsController#create as */*
Parameters: {"group"=>{}, "authenticity_token"=>"EjAsrE07jziAMLt918Mgid4PSpRFfjIaz+d9ZCxmbTo="}
So, the server doesn't seem to be receiving the POST data. i.e. the 'object' with name/description/etc.
A few things I find strange:
It seems to be receiving an empty 'group' hash, but I have no idea where this would be coming from.
Is this strange: 'Processing by GroupsController#create as /'...what is the / ?
If anyone can help me, I would be very appreciative.

AccessTokenAuthorizationCodeRequestC "error":"invalid_request"

At the second call to Client.ProcessUserAuthorization(); after I get the code from the oauth server, I get an exception: Error occurred while sending a direct message or getting the response.
Here is the last part from the log file taken with log4net, the full log is recorded in this gist: https://gist.github.com/tonyeung/5513769
2013-05-03 15:14:41,292 (GMT-5) [10] DEBUG DotNetOpenAuth.Messaging.Channel - Sending AccessTokenAuthorizationCodeRequestC request.
2013-05-03 15:14:41,393 (GMT-5) [10] DEBUG DotNetOpenAuth.Http - HTTP POST http://localhost:38828/OAuth/Token
2013-05-03 15:14:41,450 (GMT-5) [10] ERROR DotNetOpenAuth.Http - http://localhost:38828/OAuth/Token returned 400 BadRequest: Bad Request
2013-05-03 15:14:41,450 (GMT-5) [10] DEBUG DotNetOpenAuth.Http - WebException from http://localhost:38828/OAuth/Token:
{"error":"invalid_request"}
I've uploaded the solution to https://github.com/tonyeung/dotnetopenauth
The entry point is in the about action on the home controller of the Client project.
The solution is in VS2012, the latest nuget dnoa package. Nuget restore is on.
Please note that I'm implementing pieces as I need them in order to understand how the library works. I'm sure that this error is due to a missing implementation somewhere, but I'm not sure what it is?
So it looks like I was missing implementations for IsAuthorizationValid and CreateAccessToken in the Authorization Server. Please check the github repository for the stubs i put in that makes the error go away.
EDIT:
There was also a database validation error that I didn't trap. So basically any error on the server side will cause this message it looks like.
EDIT2:
There was also an issue where if the url of the page contains any non url encoded values it will throw an invalid request. In my case, my login page had a querystring parameter of returnUrl, and I had set it to /Home, which it DID NOT like, had to be: %2FHome

Resources