I am trying to create and post a tweet using the Twitter API. I have been using Postman to help create the API requests as per the instructions and walkthroughs on the Twitter API docs. When I am using Postman with hardcoded values everything works just fine and I can successfully post to twitter. The issue is when I try and create a unique signature to pass into the request, I get a 401(Unauthorized) from the twitter error response.
I follow the steps in the Twitter API docs at https://developer.twitter.com/en/docs/authentication/oauth-1-0a/creating-a-signature. And my outputs are identical in structure to the provided examples.
This is how I create the unique parameters:
To percentile encode the values I use encodeURIComponent()
oauth_nonce:
let OAUTH_NONCE = uuid.v1();
(uuid is one of many recommended way to create a random nonce, I have tried different ways but nothing works, also twitter says this can be any set of random alphanumerical strings)
oauth_timestamp:
let OAUTH_TIMESTAMP = Math.floor(Date.now() / 1000)
I create the parameter string like:
let parameterString = `include_entities=true&oauth_consumer_key=${CONSUMER_KEY}&oauth_nonce=${OAUTH_NONCE}&oauth_signature_method=${SIGNATURE_METHOD}&oauth_timestamp=${OAUTH_TIMESTAMP}&oauth_token=${ACCESS_TOKEN_KEY}&oauth_version=1.0&status=${encodedText}`
(The encoded text is percent encoded string that is being posted)
I then percent encode the parameter string and the base url which is ('https://api.twitter.com/2/tweets') to create a signature base string that looks like this
let signatureBaseString = `POST&${encodedURL}&${encodedParameterString}`
I create a signing key by encoding both the consumer secret token and access token secret
let signingKey = `${encodedConSecret}&${encodedOAuthSecret}`
I then use CryptoJS to create a hashed string:
let hash = CryptoJS.HmacSHA1(signatureBaseString, signingKey)
Then finally I create the signature like this:
let OAUTH_SIGNATURE = encodeURIComponent(Base64.stringify(hash))
I pass all that information into the config header for an axios post request.
Here is my config for the headers:
let config = {
method: 'post',
url: 'https://api.twitter.com/2/tweets',
headers: {
'Authorization': `OAuth oauth_consumer_key="${CONSUMER_KEY}",oauth_token="${ACCESS_TOKEN_KEY}",oauth_signature_method="HMAC-SHA1",oauth_timestamp="${OAUTH_TIMESTAMP}",oauth_nonce="${OAUTH_NONCE}",oauth_version="1.0",oauth_callback="https%3A%2F%2F127.0.0.1",oauth_signature="${OAUTH_SIGNATURE}"`,
'Content-Type': 'application/json',
},
data : data
};
Here are two exampled of the headers taken from the Network tab in the chrome dev tools. One is a success with hardcoded values from Postman and the fail is from the unique parameters that I created. The consumer key and oauth token are removed for security sake.
SUCCESS from hard coded Postman:
OAuth oauth_consumer_key="CONSUMER_KEY",oauth_token="OAUTH_TOKEN",oauth_signature_method="HMAC-SHA1",oauth_timestamp="1637279149",oauth_nonce="Ry6ldroxEyM",oauth_version="1.0",oauth_callback="https%3A%2F%2F127.0.0.1",oauth_signature="G7AoS6gk1MyI3Eoc6o%2F%2Bp8dM4o8%3D"
FAIL from created parameters:
OAuth oauth_consumer_key="CONSUMER_KEY",oauth_token="OAUTH_TOKEN",oauth_signature_method="HMAC-SHA1",oauth_timestamp="1637279767",oauth_nonce="a8qgwtye6tw",oauth_version="1.0",oauth_callback="https%3A%2F%2F127.0.0.1",oauth_signature="an%2BpRdqwrqLsx9%2BS%2BrCqXY1omEw%3D"
Now I do not think its an issue with the signature, as I used the Twitter Doc example and got the same output as them, so the calculations for that seem to work just fine. My guess is that the problem is with the parameter string value, but I have tried a few different values but nothing seems to work. Again it works just fine with hardcoded values from Postman and I followed the examples and received similar outputs so I am a bit confused on why I receive the 401(Unauthorized) error. Any insight would be much appreciated, Thanks!
Related
I made an api using Net.Core 'https://localhost:44351/api/usuarios' with Authorize attribute for use a validation token for access to this api. This token is generated by another api and works well.
When i use Postman for acess to api 'https://localhost:44351/api/usuarios' i need put in the Authorization tab the token previously generated (see https://i.ibb.co/Lg7rD4N/2.png) and this way i get access for the api (see https://i.ibb.co/0BqnPhR/3.png)
But the huge problem is when i try from a JAVASCRIPT CLIENT use method GET using FETCH. I know need to do a object like this for make correct request
let params= { method: 'GET',
headers: {"X-Auth-Token": "5f5fe128570248a9bd198add1a5b25e4"}
};
So my question is how i can implement the attributte 'Temporary-Headers' in the object 'params' like Postman does ( https://i.ibb.co/0BqnPhR/3.png)?
"Temporary Headers" are just like any other Header, those are just values auto-generated by the web client. I believe your problem relies on how you send your Header if you are using the fetch API modify your parameters like the following.
{
method: 'GET',
headers: {
"Authorization": "Bearer <replace with your token>"
}
}
This is how postman is sending the request as seen in the screenshots you provide.
So I've been researching this for days and have not been able to find the answer online. I'm creating an API in AWS API Gateway and noticed the difference between 'path parameters' and 'query parameters'. I already read and know the differences, when each of them should be used, etc. However, what I can not find is HOW to implement and send the path parameters?
For example, when it comes to query parameters you can send those in the 'data' part of ajax jQuery. Easy. But again, how can I include the path parameters in that ajax call? I can set the path on API GATEWAY but not sure how to send the data for it from the front end. Any help would be greatly appreciated. Thanks.
Example: root/{Animal}/
How to send the "animal" i.e. 'dog' as a path parameter instead of a query parameter? i.e. /?animal=dog
You just need to form the URL string, and don't send any data with that.
let animal = 'dog';
$.ajax({
url: serviceUrl + '/' + animal,
method: 'GET',
success: function(res) { // your code }
});
If you are taking input from a textbox with id txtSearchAnimal:
let animal = $('#txtSearchAnimal').val();
And use the above ajax call.
I am sending a request through fetch API in react application.
The fetch url contains the name argument, I should be able to create an account for the username which contains % in it. But when i tried to pass this url, i am getting the error message as unable to decode.
Note : This is http request
Format URL : http://localhost/users/api/service/username=test12%,cn=Administrators,cn=test administration,o=nmc
The space between test and administrator converts to %20 as expected.
But the % is not allowing me to pass this request.
let constructed_URL = 'http://localhost/users/api/service/username=test12%,cn=Administrators,cn=test administration';
fetch(constructed_URL, {
method: "get",
headers: urlParameter
})
I expect the browser to decode %, and pass this request.
fetch or console.error or Chrome somewhere automagically applies decodeURI (or -Component) if it thinks it was doubly encoded.
It doesn't behave that way if the URL is encoded thrice.
I wanted to use URIencoded file names in my file system directly. It simply is impossible to fetch these files at the moment.
I'm creating a OTP type of registration for my react native based mobile app. By using google cloud function to generate otp and post http request to my SMS provider.
The problem i am facing is that, whenever i try to add the random code to my sms provider url with ${code}, the message simply displays the same ${code} not the randomly generated code.
In other words, don't know how to interpolate the code into my url (as i am a newbie).
Here is my code for Random Number :
const code = Math.floor((Math.random() * 8999 + 1000));
And my request using request package is as follows:
const options = {
method: 'POST',
uri: 'http://smsprovider.com/numbers=${numbers}&route=2&message=Your OTP is ${code}',
body: {
numbers: phone,
code: code
},
json: true
};
So, whenever I get a message, it says Your OTP is ${code}. But what I actually need is to show the random number generated by the math.floor function. Expected "Your OTP is 5748"
Kindly guide
For string interpolation with JavaScript be sure to use the
`
character instead of
'
Try this instead:
const options = {
method: 'POST',
uri: `http://smsprovider.com/numbers=${numbers}&route=2&message=Your OTP is ${code}`,
body: {
numbers: phone,
code: code
},
json: true
};
String interpolation and url encoding are two distinct paradigms, one doesn't replace the other.
string interpolation allows you to dynamically insert a variable's content into a string with ${}. For this to work you must enclose your string between back quotes as #Ben Beck instructed. Some interpreters will be forgiving, meaning that even if you use single quotes, the interpreter will nonetheless parse the string with the interpolation, however not all interpreters do that, and it is bad practice to rely on it. Make sure you format these correctly.
url component encoding converts the url parameters containing special characters into a valid uri component with encodeURIComponent(). This is how you get rid of spaces and other special characters, however it might not be needed here as most browsers do that for you. Use Chrome to be sure, but again it is good practice to write fully portable code, I recommend to encode any parameter featuring any special character.
The fact that your Postman test failed is most certainly due to a faulty request. Check this screenshot for a working Postman POST request based on your case, leveraging Pre-request Script.
While testing with your code directly (not through Postman), if you keep getting the literal ${code} in place of the actual value, it likely means that the definition const code = Math.floor((Math.random() * 8999 + 1000)) is not in the same scope as the interpolation call. Check below for an example of working script using both string interpolation and url encoding based on your case:
const request = require('request');
const code = Math.floor((Math.random() * 8999 + 1000));
var p1 = encodeURIComponent(`Your OTP is ${code}`);
var uri = `http://smsprovider.com/?message=${p1}`;
const options = {
method: 'POST',
url: uri,
json: true
};
function callback(error, response, body) {
if (!error && response.statusCode == 200) {
console.log(body);
}
else {
console.log(error);
}
}
request(options, callback);
same but without url encoding and with the message parameter embedded in body element:
var uri = `http://smsprovider.com/`;
const options = {
method: 'POST',
url: uri,
body: {
message: `Your OTP is ${code}`,
},
json: true
};
I've come across this problem a few times now and I feel like there's someone out there who knows a better way to troubleshoot api calls than i - specifically request headers.
Often when i need to pass my api token via a request header, I am constantly groping at the exact format to pass my key's (it seems there's not a universal format for doing this).
For example, I am currently trying to access the vultr v1 api. The docs give a curl example where API-Key: SOMEKEY needs to be passed, yet, my first attempt rarely works then i'm just groping... Do they want my key in a key/value pair or a single string in an array? Do i use es6 objects (without quotes) or not.
here's what i mean:
// one method
const opts = {
headers: {
API-Key: 'SOMEKEY'
}
}
// another
const opts = {
'headers': {
'API-Key': 'SOMEKEY'
}
}
// another
const opts = {
headers: [
'API-Key: SOMEKEY'
]
}
axios.get(url, opts).then(res => console.log(res.data))
which is the proper way? In the curl example given by vultr it shows:
curl -H 'API-Key: EXAMPLE' https://api.vultr.com/v1/iso/list
I also see in my network inspector that the request headers show i am passing my API key yet i am still getting a 403 (bad key error)
I have double checked the validity of my key and that's not the problem.
My question is this:
How do i find the correct format for the headers? Is there a better troubleshooting method for this kind of problem? Any help would be greatly appreciated. Thanks ya'll
UPDATE:
Turns out they've got access control based on IP's. I hadn't noticed it till just now. They were blocking my request because of this. My question still stands however. Good methods for figuring out correct formats? Is there a correct format?
One way is setting Headers while creating axios object, as follows :
axios = axios.create({headers: {'API-Key': 'EXAMPLE'}});
axios.get(url, opts).then(res => console.log(res.data))
Or
axios.get(url, {headers: {'API-Key': 'EXAMPLE'}}).then(res => console.log(res.data))