How to convert cURL to Axios request - node.js

I am trying to convert a cURL request from here to Axios.
curl -d "grant_type=client_credentials\
&client_id={YOUR APPLICATION'S CLIENT_ID}\
&client_secret={YOUR APPLICATION'S CLIENT_SECRET}"\
https://oauth.nzpost.co.nz/as/token.oauth2
This works fine (when I put my credentials in).
I tried the following code:
import axios from "axios";
async function testApi() {
try {
const b = await axios.post("https://oauth.nzpost.co.nz/as/token.oauth2", {
client_id: "xxxxxxxxxxxxxxxxxxxxxxxxx",
client_secret: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
grant_type: "client_credentials"
});
} catch (error) {
console.log(error);
}
}
testApi();
This fails with Error 400. grant_type is required. I have tried putting it as a parameter, enclosing within a data: json block. I can't figure this out.

I fixed it , I needed to put the values in parameters
import axios from "axios";
async function testApi() {
try {
const b = await axios.post("https://oauth.nzpost.co.nz/as/token.oauth2",
params: {
client_id: "xxxxxxxxxxxxxxxxxxxxxxxxx",
client_secret: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
grant_type: "client_credentials"
});
} catch (error) {
console.log(error);
}
}
testApi();

curl -d is a shorter way of saying curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -d. It is a POST request even though -X POST is not specified!
So make sure you configure your Axios request as a POST request, while also ensuring your data is URL Encoded with the Content-Type header set to application/x-www-form-urlencoded. For example...
const response = await axios({
url: 'example.com',
method: 'post',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
// For Basic Authorization (curl -u), set via auth:
auth: {
username: 'myClientId',
password: 'myClientSecret'
},
// This will urlencode the data correctly:
data: new URLSearchParams({
grant_type: 'client_credentials'
})
};

Paste your command
curl -d "grant_type=client_credentials&client_id=aaaaaaaa&client_secret=bbbbbbb" https://oauth.nzpost.co.nz/as/token.oauth2
into https://curlconverter.com/node-axios/ and it will convert it into
const axios = require('axios');
const response = await axios.post(
'https://oauth.nzpost.co.nz/as/token.oauth2',
new URLSearchParams({
'grant_type': 'client_credentials',
'client_id': 'aaaaaaaa',
'client_secret': 'bbbbbbb'
})
);
or many other libraries such as fetch(), Python's requests etc.

Related

Axios (doesn't work) vs Postman (works) difference - Google OAuth2 call to refresh an access token

I'm using the Google OAuth2 flow, writing a function that takes a refresh_token I've saved to the database and makes the call to obtain a refreshed access_token. The problem is that when I make the call via Postman, it succeeds, but when I try to do it in the code via axios, it fails.
My Postman configuration for the call looks like this:
My code snippet looks like this:
export const getNewAccessToken = async (refreshToken: string): Promise<string> => {
const url = 'https://oauth2.googleapis.com/token';
const data = {
refresh_token: refreshToken,
grant_type: "refresh_token",
client_id: process.env.GOOGLE_CLIENT_ID,
client_secret: process.env.GOOGLE_CLIENT_SECRET,
};
try {
let res = await axios.post(url, data, {
headers: {
'content-type': 'application/x-www-form-urlencoded'
},
}).then(response => {
debugger;
}).catch(e => {
// It always enters the 'catch' here
debugger;
});
} catch (e) {
debugger;
}
}
I've checked and the refresh_token I'm using to test this, client_id and client_secret are the same in both cases.
When I make this call, the error in the catch shows a 400 Bad Request, and the response.data is {error: 'unsupported_grant_type', error_description:'Invalid grant_type: '}
Am I missing something obvious? What can I try to do to debug?
One thing I've tried is to look at the error e to see what request is being made, but I can't seem to find where the original request is in that ClientRequest object.
Edit 1:
Here's the curl command from Postman:
curl --location --request POST 'https://oauth2.googleapis.com/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'refresh_token=[confirmed same refresh_token as the code]' \
--data-urlencode 'client_id=[ditto]' \
--data-urlencode 'client_secret=[ditto]' \
--data-urlencode 'grant_type=refresh_token'
If you give Axios a JavaScript object to send as a request body, Axios will serialize it to JSON. But in this case, you are setting the Content-Type header to application/x-www-form-urlencoded which signals intent to provide a URL-encoded body, not JSON. A URL-encoded body looks like this:
refresh_token=abc&grant_type=abc&client_id=abc&client_secret=abc
There are quite a few different ways to create such a string to send as the body, a number of which are detailed in the Axios documentation. I personally would do the following:
const data = new URLSearchParams({
refresh_token: refreshToken,
grant_type: 'refresh_token',
client_id: process.env.GOOGLE_CLIENT_ID,
client_secret: process.env.GOOGLE_CLIENT_SECRET,
});
Alternatively, it might also work if you just set the Content-Type header to application/json instead, but that depends on the API and whether it is able to accept JSON.
Try this code
export const getNewAccessToken = async (refreshToken: string): Promise<string> => {
const url = 'https://oauth2.googleapis.com/token';
const data = new URLSearchParams({
refresh_token: refreshToken,
grant_type: 'refresh_token',
client_id: process.env.GOOGLE_CLIENT_ID,
client_secret: process.env.GOOGLE_CLIENT_SECRET,
});
try {
let res = await axios.post(url, data, {
headers: {
'content-type': 'application/x-www-form-urlencoded',
'Accept-Charset': 'UTF-8'
},
}).then(response => {
debugger;
}).catch(e => {
// It always enters the 'catch' here
debugger;
});
} catch (e) {
debugger;
}
}

How to make a curl request using axios with curl options

I have to make a curl request to jenkins to get the job done but I am not sure how to do that using axios I am currently using nestjs as my backend framework I have tried googling it not much luck If anybody please help. The curl request looks a bit like below
curl -u pp:11d7b5072400da385981e24283472834 -H "${JENKINS_CRUMB}" -i -X POST $JENKINS_URL/job/$JOB_NAME/buildWithParameters --user pp:1232343454564123453 --data token=123456 --data
According to axis documents you can create request like that:
const JENKINS_URL = '***';
const JOB_NAME = '***';
const options = {
method: 'POST',
url: `${JENKINS_URL}/job/${JOB_NAME}/buildWithParameters`,
headers: {
JENKINS_SAMPLE_HEADER: 'jenkins_smaple_header'
},
withCredentials: true,
auth: {
username: 'pp',
password: '11d7b5072400da385981e24283472834'
},
data: {
token: '123456',
}
};
axios (options)
.then(function(response) {
console.log(response);
}).catch(function(error) {
console.error('Error', error);
});
I used this lovely tool and obtained this - after fixing a couple of errors in the original request:
const axios = require('axios');
const response = await axios.post(
'http://path',
new URLSearchParams({
'token': '123456'
}),
{
auth: {
username: 'pp',
password: '1232343454564123453'
}
}
);
It's quite useful to help out when you don't know how to translate a request!

node-fetch send post request with body as x-www-form-urlencoded

i want to send a post request using node-fetch with a body payload encoded in the x-www-form. I tried this code but unfortunately it doesnt work:
paypalSignIn = function(){
var username = process.env.PAYPALID;
var password = process.env.PAYPALSECRET;
var authContent = 'Basic '+base64.encode(username + ":" + password);
fetch('https://api.sandbox.paypal.com/v1/oauth2/token', { method: 'POST',
headers: {
'Accept': 'application/json',
'Accept-Language' :"en_US",
'Authorization': authContent,
'Content-Type': 'application/x-www-form-urlencoded'
},
body: 'grant_type=client_credentials' })
.then(res => res.json()) // expecting a json response
.then(json => console.log(json));
}
I'm not sure if this way is possible but i need to use this standard for die paypal api.
I'm getting statu code 400 with error
grant_type is null
Thx
I don't know if this is the only error, but at the very least you need a space between the word Basic and the encoded username/password.
Next time you ask a question, also post what your script returned. I'm guessing it was a 401 error in this case.
I used the PayPal sandbox today, here is how I managed to get my access token and a successful response (and also answering the OP's question about sending application/x-www-form-urlencoded POST requests with data) =>
I did it with node-fetch but the plain fetch API should work the same.
import fetch from "node-fetch";
export interface PayPalBusinessAccessTokenResponseInterface {
access_token: string;
}
export interface PayPalClientInterface {
getBusinessAccessToken: (
clientId: string,
clientSecret: string
) => Promise<PayPalBusinessAccessTokenResponseInterface>
}
const paypalClient: PayPalClientInterface = {
async getBusinessAccessToken(
clientId: string,
clientSecret: string
): Promise<PayPalBusinessAccessTokenResponseInterface> {
const params = new URLSearchParams();
params.append("grant_type", "client_credentials");
const paypalAPICall = await fetch(
"https://api-m.sandbox.paypal.com/v1/oauth2/token",
{
method: "POST",
body: params,
headers: {
"Authorization": `Basic ${Buffer.from(clientId + ":" + clientSecret).toString('base64')}`
}
}
);
const paypalAPIRes = await paypalAPICall.json();
return paypalAPIRes;
}
};
export default paypalClient;

Instagram API: Invalid Platform App when fetching access token

I'm trying to log in using Instagram Basic Display API.
I'm trying to get the access_token, and I'm using axios:
const { code } = queryParams;
const url = `https://instagram.com/oauth/access_token`;
const result = await axios.request({
url,
method: 'POST',
data: {
'client_id': INSTAGRAM_CLIENT_ID,
'client_secret': INSTAGRAM_CLIENT_SECRET,
'grant_type': 'authorization_code',
'redirect_uri': 'https://localhost:3000/auth/instagram/token',
code,
},
});
I'm getting a 400 error, with the message invalid platform app. All the values sent exist and are correct.
My redirect_uri doesn't exist though, but it's added to the authorized URL list. It doesn't exist because I don't have https in my local server.
I had this same issue. The official example given by Instagram using curl uses the -F tag, which means that they are posting the data as the application/x-www-form-urlencoded content-type.
Every other post format I tried is ignored. Changing your code to post as a form and it should work.
There is a very good answer on this post
const querystring = require('querystring');
//Make Object with params const data = {
client_id: 'xxxxxxx',
client_secret: 'xxxxxxxxxxx',
grant_type: 'authorization_code',
redirect_uri: 'https://example.com/auth',
code: 'xxxx' }
//Make the Call
axios.post("https://api.instagram.com/oauth/access_token",
querystring.stringify(data)) .then(function (response) {
console.log("OK", response.data); }) .catch(function (error) {
console.log(error); });

Axios Basic Auth with API key Example in Node

There is a curl request like this:
curl -X GET --header 'Accept: application/json' --header 'Authorization: Basic [==APIKEYHERE==]' 'https://apipath.com/path?verbose=true'
I removed the APIKEY and the API path for privacy.
The curl request is working fine, I can't figure out how to convert this into an Axios request since it only needs an API key and not a username and password.
Here is the example I found:
axios.get('https://apipath.com/path?verbose=true', {}, {auth: {username: 'username', password: 'password'}})
.then(function(response) {
console.log(response.data, 'api response');
})
I'm not sure how to get this to work for my case?
The short answer to adding an X-Api-Key to an http request with axios can be summed up with the following example:
const url =
"https://someweirdawssubdomain.execute-api.us-east-9.amazonaws.com/prod/custom-endpoint";
const config = {
headers: {
"Content-Type": "application/json",
},
};
// Add Your Key Here!!!
axios.defaults.headers.common = {
"X-API-Key": "******this_is_a_secret_api_key**********",
};
const smsD = await axios({
method: "post",
url: url,
data: {
message: "Some message to a lonely_server",
},
config,
});
I was stuck for 8 hours trying to figure this out as the errors lined up in the queue, adding the key to the default headers was the only way I could get this to work.
Given the cURL command including --header 'Authorization: Basic [==APIKEYHERE==]', you know that the server wants a header sent using the Basic authentication scheme. That means that your API key is both the username and password joined by a : and encoded with Base64. So, you can decode what the username and password should be by decoding your API key with Base64 and seeing the values joined by the colon.
Consider the spec detailed on MDN: Authorization Header
So if your API key is Ym9iOnBhc3N3b3JkMQ==, and you decode it with Buffer.from("API_KEY", "base64").toString(), you would get the value bob:password1 meaning your username is bob and your password is password1 making your request:
const [username, password] = Buffer.from("YOUR_API_KEY", "base64").toString().split(":");
axios.get('https://apipath.com/path?verbose=true', {}, {
auth: {
username,
password
}
})
.then(function(response) {
console.log(response.data, 'api response');
})
You can define a function like this, then you can pass the token to header after login success.
import axios from "axios";
const setAuthToken = token => {
if (token) {
// Apply to every request
axios.defaults.headers.common["Authorization"] = token;
} else {
// Delete auth header
delete axios.defaults.headers.common["Authorization"];
}
};
axios.get('https://apipath.com/path?verbose=true', {}, {auth: {username: 'username', password: 'password'}})
.then(() => setAuthToken(response.token));

Resources