Axios Basic Auth with API key Example in Node - node.js

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));

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!

getting 404, firebase + node.js, using "projects.locations.instances.create"

I'm trying to make an instance of a database with node.js in firebase realtime database.
My node.js route looks like this:
const axios = require('axios');
var {google} = require("googleapis");
var serviceAccount = require("paht/to/json");
router.post('/createnewdatabase', function (req, res) {
//scopes used for the create
var scopes = [
"https://www.googleapis.com/auth/cloud-platform",
"https://www.googleapis.com/auth/firebase"
];
// Authenticate a JWT client with the service account.
var jwtClient = new google.auth.JWT(
serviceAccount.client_email,
null,
serviceAccount.private_key,
scopes
);
// Use the JWT client to generate an access token.
jwtClient.authorize(function(error, tokens) {
if (error) {
console.log("Error making request to generate access token:", error);
} else if (tokens.access_token === null) {
console.log("Provided service account does not have permission to generate access tokens");
} else {
var accessToken = tokens.access_token;
let apiKey = req.body.apiKey;
const config = {
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + accessToken
},
};
axios({
method: 'post',
url: 'https://firebasedatabase.googleapis.com/v1beta/projects/{project-id}/locations/europe-west1',
data: {
key: apiKey,
databaseId: 'segesggseg-656-sdgsdgs',
},
config
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
res.send('POST request to the homepage')
}
});
})
I'm getting a 404 when trying to call the route. I'm guessing it's something with the tokens. The documentation is here: https://firebase.google.com/docs/reference/rest/database/database-management/rest/v1beta/projects.locations.instances/create
I can't figure it out :-)
Please consider that according to the official documetation link:
"name field - Currently the only supported location is 'us-central1'."
I was able to create an instance using the api only with empty data parameter.
'https://firebasedatabase.googleapis.com/v1beta/projects/111111111111/locations/us-central1/instances?databaseId=myinstanceiddd&validateOnly=true&key=[YOUR_API_KEY]' \
--header 'Authorization: Bearer [YOUR_ACCESS_TOKEN]' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{}' \
--compressed
200
{
"name": "projects/111111111111/locations/us-central1/instances/myinstanceiddd",
"project": "projects/111111111111",
"databaseUrl": "https://myinstanceiddd.firebaseio.com",
"type": "USER_DATABASE",
"state": "ACTIVE"
}
After answer above did not work for me... I was forced to read docs (https://firebase.google.com/docs/reference/rest/database/database-management/rest/v1beta/projects.locations.instances/create) word by word...
Second paragraph says that ur project needs to be on the Blaze plan in order to be able to create instance... After this doing this, it now works for me.

How to pass application credentials through apollo client like we do with axios auth options

I wanted to know how to pass application credentials (or even user credentials through code) to apollo client like we do in axios.
In axios -
const data = await axios({
method: "POST",
url: `${SOME_URL}`,
auth: {
username: USER, //like this//
password: PASS,
},
data: req.body,
headers: { Accept: "application/json" },
});
For apollo client I have used apollo-link-http, my setup looks like this -
import fetch from "unfetch";
import { ApolloClient } from "apollo-client";
import { from } from "apollo-link";
import { onError } from "apollo-link-error";
import { createHttpLink } from "apollo-link-http";
const client = new ApolloClient({
link: from([errorLink, standardVariablesLink, typenameCleanerLink, createHttpLink({ uri: "https://graphql-backend/graphql", fetch })]),
cache,
});
I have tried adding credentials option in createHttpLink object as credentials: ${USER}:${PASS} OR as an object
credentials: {
user: USER,
password: PASS
}
but that didn't work.
Any help appreciated. Thanks!!
Question:
What is this auth in axios? ... a bit of searching: basic auth options! axios internally converts it to header.
Apollo client is not so nice ... you need to convert params into header itself and use this way:
const link = createHttpLink({
headers: {
authorization: "Basic btoa_converted_username_password";
},
The auth option in axios is just a shorthand way of constructing a Basic Authorization header. In order to construct the credentials value to include in the header, you do the following:
The username and the password are combined with a colon (aladdin:opensesame).
The resulting string is base64 encoded (YWxhZGRpbjpvcGVuc2VzYW1l).
So you can do something like:
createHttpLink({
uri: '...',
headers: {
Authorization: `Basic ${window.btoa(`${username}:${password}`)}`,
}
})
If you're running this code in Node.js, you would use the following instead of btoa:
Buffer.from(`${username}:${password}`).toString('base64')
Also note that if this code is running client-side, you probably want to inject the headers dynamically by using setContext instead.

How to convert cURL to Axios request

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.

Resources