I have successfully gotten an access_token, so it's not a problem with the 3-legged process.
The problem starts when I try to add a new post/activity using the Buzz API...
Here is my request:
POST /buzz/v1/activities/#me/#self?alt=json HTTP/1.1
Host: www.googleapis.com
Connection: close
Accept-encoding: gzip, deflate
User-Agent: Zend_Http_Client
Content-Type: application/json
Authorization: OAuth
realm="",oauth_consumer_key="example.com",oauth_nonce="ce29b04ce6648fbb92efc8f 08c1c0091",oauth_signature_method="HMAC-
SHA1",oauth_timestamp="1277934794",oauth_version="1.0",oauth_token="1%2FcBz o5ckGvCAm3wLWh1SDH3xQNoW--
yek1NVfUa1Qqns",oauth_signature="CUezSiMbvxyN1BTeb3uROlIx8gA%3D"
Content-Length: 86
{"data":{"object":{"type":"note","content":"posting on Buzz"}}}
Here is the response:
{"error":{"errors":[{"message":"Unknown authorization header","locationType":"header","location":"Authorization"}],"code":401,"message":"Unknown authorization header"}}
And here is my base string (the string that the signature gets generated from):
POST&https%3A%2F%2Fwww.googleapis.com%2Fbuzz%2Fv1%2Factivities%2F%40me
%2F%40self&oauth_consumer_key%3Dexample.com%26oauth_nonce
%3D50acc6b7ac48304ae9301134d6988cdb%26oauth_signature_method%3DHMAC-
SHA1%26oauth_timestamp%3D1278065599%26oauth_token
%3D1%252FcBzo5ckGvCAm3wLWh1SDH3xQNoW--yek1NVfUa1Qqns%26oauth_version
%3D1.0
I've even tried this other base string (with the alt=json added in):
POST&https%3A%2F%2Fwww.googleapis.com%2Fbuzz%2Fv1%2Factivities%2F%40me
%2F%40self%3Falt%3Djson&oauth_consumer_key%3Dexample.com%26oauth_nonce
%3Dee8704244623bbcc860bf77bfcadeacc%26oauth_signature_method%3DHMAC-
SHA1%26oauth_timestamp%3D1278069221%26oauth_token
%3D1%252FcBzo5ckGvCAm3wLWh1SDH3xQNoW--yek1NVfUa1Qqns%26oauth_version
%3D1.0
I have tried pretty much everything to get this working - not sure why it always says 'Unknown authorization header'... the header looks fine when compared to other ones that work.
Any ideas?
which endpoint did you use to authorize request token?
developer's guide:
Important: Part of the OAuth process
requires that you direct the user to
the Google Authorization service to
approve access for your application.
Google Buzz requires that you use a
different Authorization service
endpoint, located at
https://www.google.com/buzz/api/auth/OAuthAuthorizeToken.com/buzz/api/auth/OAuthAuthorizeToken.
You should use GET or POST method (depending what request you use). By default Zend uses header-method.
$client->setMethod(Zend_Http_Client::GET);
Related
I'm posting this on my way home, so forgive the lack of code but I'll try to be as detailed as possible and add code when I can tonight. So essentially I have a react native app using redux and axios. A brief review (code to follow) may explain that I'm doing something wrong.
Serviceapi.js
Creates and exports basic axios with base url.
const ServiceApi = axios.create({
baseURL: BASE_URL,
responseType: 'json'
});
AuthReducer.js
On login sets Authorization header manually using the post method. This works on both android and ios the login is returned and I use the authorization header.
return {
type: PERFORM_LOGIN,
payload: {
user: {
name: username
},
request: {
url: '/login',
method: 'post',
headers: {
'Authorization': 'Basic ' + basicAuth
}
}
}
On login, I return the following redux-axios action, you can see that I set the header: Authorization manually, this works great.
// On login success, set the authInterceptor responsible for adding headers
authInterceptor = ServiceApi.interceptors.request.use((config) => {
console.log(`Attaching Authorization to header ${basicAuth}`);
config.headers.common.Authorization = basicAuth;
return config;
}, (error) => {
Promise.reject(error);
});
On logout I clear the interceptor. I chose to add and remove on login and logout instead of always having it there just because. This could be a problem but it was fine for Android
// Clear the auth interceptor
ServiceApi.interceptors.request.eject(authInterceptor);
Again this is all working great on Android. And it looks to be working on ios. When I debug the interceptor it's getting called and setting the header.
But I get back a 403 on ios. After looking at the request in more detail, there is a big difference between the android header in the request and the ios header in the request. The rest of the request object is the same, only the _header object is different between ios and android.
Android Request
_headers:
accept: "application/json, text/plain, */*"
authorization: "Basic <correct base64 value>"
content-type: "application/json;charset=utf-8"
__proto__: Object
IOS Request
_headers:
accept: (...)
authorization: (...)
content-type: (...)
get accept: ƒ ()
set accept: ƒ ()
get authorization: ƒ ()
set authorization: ƒ ()
get content-type: ƒ ()
set content-type: ƒ ()
__proto__: Object
With the differences, setting a breakpoint at looking at the console for error.request._headers.authorization; I get the same "Basic: " contents as the Android header contains.
index.php
The backend service is a php file that does a $_SERVER['PHP_AUTH_USER'] which fails a 403 if not set which is what's happening. I don't have access to the php, I was just told this is what it's using.
Again I apologize for not providing code but i will when I get a chance later. Is there something maybe I have to set extra for ios? Or maybe php for ios needs an extra header?
Code to follow.
EDIT Updated with code, hopefully I didn't leave in any of the encoded login info.
EDIT 2 Upon further investigation this looks like it's related to apache/PHP rather than react-native/axios. I threw together an express server that simulated the same checking that the PHP does:
- Look for the Authorization header
- Print it
- Return back 403 or 200 w/ data based on that
When running pointing at http://localhost:3000 using the exact same app on the emulator I get back what I'm expecting. To add to this, when I'm on the emulator, I can't actually login to the live URL (even though I could on the regular device), I get the same 403 error but this time a little earlier.
EDIT 3
To provide some more information from the server, here are the three requests that I've been able to log:
1) This is from the IOS Emulator iPhone8 against a an express server:
accept:"application/json, text/plain, */*"
accept-encoding:"gzip, deflate"
accept-language:"en-us"
authorization:"Basic <base 64 encoding>"
connection:"keep-alive"
content-length:"0"
host:"localhost:3000"
user-agent:"MobileApp/1 CFNetwork/978.0.7 Darwin/18.5.
2) This is from the same emulator to apache/PHP (5.3.3), we can see there is no Authorization header.
Accept: application/json, text/plain, */*
User-Agent: MobileApp/1 CFNetwork/978.0.7 Darwin/18.5.0
Accept-Language: en-us
Accept-Encoding: br, gzip, deflate
Connection: keep-alive
3) This is from Android to apache/PHP (5.3.3):
authorization: Basic <Base 64 encoding>
Host: api.serviceurl.com
Connection: Keep-Alive
Accept-Encoding: gzip
User-Agent: okhttp/3.12.1
Edit 4
So after playing around and googling for some time, it turns out that the issue is with Zend Framework and fastcgi which automatically removes the Authorization header. The weird thing is that it's only doing it from IOS and not from Android, which makes no sense really.
On thing we noticed in the logs, is that it's accepting the Android and Postman as POST but it's logging the IOS requests as GET. I'm not entirely sure what's up with that, but it seems to be another difference. I've updated the task to have zend as a tag. There are a number of SO articles on resolving this with ReWriteMod on apache/zend so I'll give those a go first and see if it fixes the issue.
** Edit 5**
So far we've attempted to follow the SO articles which ask that that that following be added (Authorization header missing in django rest_framework, is apache to blame?):
SetEnvIfNoCase Authorization ^(.*) -e=PHP_HTTP_AUTH
RewriteCond %{HTTP:Authorization} ^(.*)
RewriteRule .* - [e=HTTP_AUTHORIZATION:%1]
which results in the following:
// IOS
_SERVER[PHP_HTTP_AUTH] = <blank>
_SERVER[HTTP_AUTHORIZATION] = <blank>
// Android
_SERVER[PHP_HTTP_AUTH] = Username
_SERVER[HTTP_AUTHORIZATION] = Basic <Base65 encoded>
_SERVER[PHP_HTTP_PW] = Password
So we know that Header Authorization is getting to Apache, but now it's coming through as blank. There are a few other SO answers I'm researching but the search continues...
Edit 6
Resolved(ish)
Turns out it was a trailing slash required on the request for IOS. I was able to find this link https://github.com/square/retrofit/issues/1037 where the the issue was described as:
For those interested: We are using Django as our backend and by default when you do
not provide a trailing slash on the endpoint Django redirects from the non-slash
endpoint to the slash endpoint.
Now, we aren't using Django, but apparently for our configuration of Zend it was
the same issue - Android was able to re-direct without issue, while IOS was not. Another comment on the task states:
OkHttp strips the "Authorization" header when redirected across hosts (connections)
via a 3xx response from the original host.
Which doesn't seem accurate, since Android was using OkHttp and was working fine. It looked like IOS using Darwin had the issue.
EDIT
I forgot something else from my original post, I also had to change my interceptor from the line config.headers.common.Authorization = ... to config.headers.Authorization = ... which for some reason kept the casing. Original way converted Authorization to authorization, while the latter kept it as Authorization. Not sure if this was an issue, but I made it anyhow.
// On login success, set the authInterceptor responsible for adding headers
authInterceptor = ServiceApi.interceptors.request.use((config) => {
console.log(`Attaching Authorization to header ${basicAuth}`);
config.headers.Authorization = basicAuth;
return config;
}, (error) => {
Promise.reject(error);
});
I cannot believe I spent 5 hours debugging and researching to resolve the issue eventually with a trailing slash! Even when I tried the trailing slash I thought it was a futile attempt but it actually resolved my issue. #kendavidson you're a lifesaver!!
I have been trying to use the Stormpath API in my website. I cannot work out how to communicate with the API through PHP. I've tried some variations of cURL but I think I'm missing something...At this stage I'm just trying to make the request from a blank page with known account details - I'm not getting any result.
The API documentation provides this example, for example. What is the simplest way for me to submit the request this using PHP?
Request
POST /oauth/token HTTP/1.1
Accept: application/json
Content-Type: application/x-www-form-urlencoded
Host: smooth-ensign.apps.stormpath.io
grant_type=password&username=jakub%40stormpath.com&password=Password1%21
Response
{
"access_token": "eyJraWQi[...]0dTpiM",
"refresh_token": "eyJraWQi[...]okvVI",
"token_type": "Bearer",
"expires_in": 3600
}
I also have the Stormpath PHP SDK installed, if that provides a better way to do this.
Hi I am trying to push the notification from rest client to android app. I am doing like below -
URL - https://android.googleapis.com/gcm/send
Method - POST
Headers - Authorization: my_server_key
I always get this message
Status Code: 401 Unauthorized
Alternate-Protocol: 443:quic,p=0.002
Cache-Control: private, max-age=0
I am not sure what I am missing & last I am using correct server api key.
Please assist & thanks in advance.
Push notification uses Web Socket. You cannot do this using HTTP protocol unless you have a server side implementation set up to respond to your request through Web Socket.
I set this values in the header then it is working fine for me.
Below is the header key & value.
A) Authorization: & it value likes key=API_KEY
B) Content-Type: application/json
I hope you are done with your request but it will help to others
You have to send like this
In head
-------
Headder Value
Authorization key=your value
Content-Type application/json
In Body
-------
Something like this
{
"registration_ids" : ["Your id"],
"data" : {
"message":"Your message"
}
}
Hope it will help
I use the following code to get the bearer token:
$token = base64_encode($client_id.':'.$client_sec);
$data = array ('grant_type' => 'client_credentials');
$data = http_build_query($data);
$header = array(
'Authorization: Basic '.$token,
'Content-type: application/x-www-form-urlencoded;charset=UTF-8',
'Content-Length: ' . strlen($data)
);
$options = array(
CURLOPT_HTTPHEADER => $header,
CURLOPT_HEADER => false,
CURLOPT_URL => 'https://api.twitter.com/oauth2/token',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POSTFIELDS => $data
);
$ch = curl_init();
curl_setopt_array($ch, $options);
$result = curl_exec($ch);
curl_close($ch);
print_r($result);
exit;
But output all the time:
{"errors":[{"label":"authenticity_token_error","code":99,"message":"Unable to verify your credentials"}]}
What I doing wrong?
After fighting with this problem for a while I found the problem was I was making the call to /oauth2/token using Advanced Rest Client from a browser I was already logged into Twitter with. After logging out of Twitter and making the API call again it worked fine.
Short answer: make sure you do not already have an active session logged into Twitter when attempting to request a Bearer token.
I struggled with this for awhile and none of the answers I've found seemed to help. The documentation for the error is also a vague "something went wrong".
My problem is that I was using a mashup of code I found, and the headers weren't used correctly:
$headers = array(
'Authorization' => 'Basic ' . base64_encode($appid . ':' . $secret), // WRONG!!!
'Authorization: Basic ' . base64_encode($appid . ':' . $secret), // Correct!
'Content-Type: application/x-www-form-urlencoded;charset=UTF-8', // Correct!
);
For me, the problem was that the Authorization header was using key-value format, while the content-type header was not. This broke the authorization header.
Here are some other things to check that also relate to error 99:
Verify that your credentials are correct and base64 encoded (see above)
Make sure the request is using POST
Ensure the content-type is set (see above)
Make sure you included grant_type=client_credentials as a post field.
SSL is required, make sure that is being used (https://)
Try verbose logging to help debugging. It should include SSL certificate information, your authorization header, and content type header. This won't show the grant_type field though, only headers.
If everything looks OK but it still won't work, you might be getting rate limited. Rate limits reset every 15 minutes.
When you finally get your access token, make sure you cache it to avoid rate limiting. You get 450 requests every 15 minutes, I believe. Half of that will be spent on getting your access token if you don't cache it!
There's an accepted answer here already but just in case someone stroll to this post and had the same issue I did...
Twitter docs for reference -> OAuth 2.0 docs
Misconception #1: The Authorization String is generated using the consumer key (aka API-Key) and consumer secret (aka API Secret Key). The display of those credentials in the UI on developer.twitter.com is less apparent than that of apps.twitter.com. Nonetheless common RIF problem.
Misconception #2: This one is not really an misconception but an implementation error when base64 encoding the url concatenated Consumer Key+":"+Consumer Secret. If not doing this programmatically be sure to check for whitespaces anywhere (especially around the :) in the concatenated string you are base64 encoding.
Just a tad bit advice as well postman has a wonderful utility that makes the rest call to retrieve an oauth2.0 token (as well as other auth tokens) this was useful for me when trying to consume api's with the that required an oauth1.0 token
After fighting with this problem, i finally come up with the solution. Twitter is not actually sending the right message if error exist anywhere.
When i send request from curl, it works fine but when through code. i was having same error {"errors":[{"label":"authenticity_token_error","code":99,"message":"Unable to verify your credentials"}]}
So what i got, problem was lying with Access control header. setting these header does not work for me
xhttp.setRequestHeader("Content-Type","application/x-www-form-urlencoded")
xhttp.setRequestHeader('Access-Control-Allow-Headers', '*');
xhttp.setRequestHeader('Access-Control-Allow-Origin', '*')
xhttp.setRequestHeader('X-Requested-With', 'XMLHttpRequest')
as a workaround i just used this url to bypass request to handler cors
https://cors-anywhere.herokuapp.com/https://api.twitter.com/oauth2/token
added "https://cors-anywhere.herokuapp.com/" before the actual url and it began to work. hope someone may face this issue in problem
Twitter OAuth 2.0 Bearer Token:
Step 1: Encode consumer key and secret
A - Concatenate the encoded consumer key, a colon character ":", and the encoded consumer secret into a single string.
B - Base64 encode the string from the previous step.
Example function: convertStringBase64("Api key" +":"+"Api key secret")
C- This steps generate you "Authorization"
Step 2: Obtain a Bearer Token
URL: https://api.twitter.com/oauth2/token
The request must be an HTTP POST request.
The request must include an Authorization header with the value of Basic <base64 encoded value from step 1>.
The request must include a Content-Type header with the value of application/x-www-form-urlencoded;charset=UTF-8.
The body of the request must be grant_type=client_credentials.
Example request (Authorization header has been wrapped):
POST /oauth2/token HTTP/1.1
Host: api.twitter.com
User-Agent: My Twitter App v1.0.23
Authorization: Basic eHZ6MWV2RlM0d0VFUFRHRUZQSEJvZzpMOHFxOVBaeVJn
NmllS0dFS2hab2xHQzB2SldMdzhpRUo4OERSZHlPZw==
Content-Type: application/x-www-form-urlencoded;charset=UTF-8
Content-Length: 29
Accept-Encoding: gzip
grant_type=client_credentials
If the request was formatted correctly, the server would respond with a JSON-encoded payload:
Example response:
HTTP/1.1 200 OK
Status: 200 OK
Content-Type: application/json; charset=utf-8
...
Content-Encoding: gzip
Content-Length: 140
{"token_type":"bearer","access_token":"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA%2FAAAAAAAAAAAAAAAAAAAA%3DAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"}
For more informtaion look this in Twitter Developer API: https://developer.twitter.com/en/docs/authentication/oauth-2-0/application-only
I'm working with a WSDL that has a different SOAP Action in the header to the one I would expect. At the moment when I call the web service, I just get like a .NET description site of a web service. In this instance it's
https://preprod.squidcard.com/ytm/sQuidpages/sQuidPWS.asmx
What URL should I actually call to get to the getPurseBalance() method as the option in the SOAP Action from the WSDL doesn't seem to be defined, is there anyway I can determine this or should I go to the web service provider?
Thanks,
You should not call a URL, you should post a XML to this direct same page. To know what to send to the web service you can check your URL:
https://preprod.squidcard.com/ytm/sQuidpages/sQuidPWS.asmx?op=getPurseBalance
Here you can also view your SoapAction and other headers to be send:
POST /ytm/sQuidpages/sQuidPWS.asmx HTTP/1.1
Host: preprod.squidcard.com
Content-Type: text/xml; charset=utf-8
Content-Length: length
SOAPAction: "https://secure.squidcard.com/getPurseBalance"
If you don't want to create XML manually you can also use the SoapClient class from PHP. You can find more information here:
http://www.php.net/manual/en/class.soapclient.php
$client = new SoapClient("https://preprod.squidcard.com/ytm/sQuidpages/sQuidPWS.asmx?WSDL");
var_dump($client->__getFunctions());
$client->__soapCall("getPurseBalance", array('your parameters'));
see this http://www.php.net/manual/en/soapclient.setlocation.php
I think you should use
$client->__setLocation('https://preprod.squidcard.com/ytm/sQuidpages/sQuidPWS.asmx');