I'm building a fullstack app with nuxt + express and I have finally managed to include an authentication between my frontend/backend with passport and jwt.
I want to make additional api requests to my own github repo for fetching the latest releases (so a user gets a information that an update exists). This requets failed with a "Bad credentials" messages. I think this happens because my jwt token is sent with it (I can see my token in the request header).
My question is, is it possible to prevent axios from sending my JWT token in only this call? First, to make my request work and second, I don't want the token to be sent in external requests.
Example:
const url = 'https://api.github.com/repos/xxx/releases/latest'
this.$axios.get(url)
.then((res) => {
this.latestRelease = res.data
}).catch((error) => {
console.error(error)
})
transformRequest
You can override the Authorization for a specific call by passing an options object to your get request and transforming your request headers:
const url = 'https://api.github.com/repos/xxx/releases/latest';
this.$axios.get(url, {
transformRequest: (data, headers) => {
delete headers.common['Authorization'];
return data;
}
})
.then((res) => {
this.latestRelease = res.data;
}).catch((error) => {
console.error(error);
})
As explained in their GitHub readme:
transformRequest allows changes to the request data before it is sent to the server.
This is only applicable for request methods 'PUT', 'POST', 'PATCH' and 'DELETE'.
The last function in the array must return a string or an instance of Buffer, ArrayBuffer,
FormData or Stream.
You may modify the headers object.
Creating a specific instance
You can create an instance of axios for different scenarios. This allows you to separate your axios calls that require an authorization header and those who don't. Each instance has its own 'global' options:
const axiosGitHub = axios.create({
baseURL: 'https://api.github.com/',
timeout: 1000,
headers: {}
});
// won't include the authorization header!
const data = await axiosGithub.get('repos/xxx/releases/latest');
You could use this answer to have several instances of axios: https://stackoverflow.com/a/67720641/8816585
Or you could also import a brand new axios and use it locally like this
<script>
import axios from 'axios'
export default {
methods: {
async callFakeApi() {
const result = await axios.get('https://jsonplaceholder.typicode.com/todos/1')
console.log('result', result)
},
}
}
</script>
Axios interceptors as mentionned by Thatkookooguy are another solution!
Related
Im setting up a Twilio Sandbox for WhatsApp
for when a message comes in I set a webhook to my application’s link.
But my application requires a bearer token.
How can I set up twilio to send our bearer token together with the request it makes to my URL?
thank you
i make all test without the bearer token and it works fine.
but to go live, we need this token autentication for security reasons.
The webhook just triggers a GET or POST request to the registered URL, as you rightfully said. To be able to add custom parameters, such as a bearer token, you need to add an intermediate step in between. This can be achieved, for example, with any Serverless function.
Naturally, using Twilio Serverless would be the easiest option to do this:
const axios = require('axios');
exports.handler = async (context, event, callback) => {
// Create a new voice response object
const twiml = new Twilio.twiml.VoiceResponse();
try {
// Open APIs From Space: http://open-notify.org
// Number of people in space
const response = await axios.request({
method: "POST",
url: `http://api.open-notify.org/astros.json`,
headers: {
"Authorization": `Bearer ${request.body.token}`,
"Content-Type": "application/json; charset=utf-8"
},
});
const { number, people } = response.data;
const names = people.map((astronaut) => astronaut.name).sort();
// Create a list formatter to join the names with commas and 'and'
// so that the played speech sounds more natural
const listFormatter = new Intl.ListFormat('en');
twiml.say(`There are ${number} people in space.`);
twiml.pause({ length: 1 });
twiml.say(`Their names are: ${listFormatter.format(names)}`);
// Return the final TwiML as the second argument to `callback`
// This will render the response as XML in reply to the webhook request
// and result in the message being played back to the user
return callback(null, twiml);
} catch (error) {
// In the event of an error, return a 500 error and the error message
console.error(error);
return callback(error);
}
};
Using Node & Axios
What I Want to Do
In my server.js file, I want to call an api for a token that always changes, use axios (or other solution) to create a global token variable, and provide the global token to an app.get request header within an object, again, all within my server.js file.
What I'm Trying
I get the data using...
var data = '<tsRequest>\r\n\t<credentials name="name" password="pword">\r\n\t\t<site contentUrl="" />\r\n\t</credentials>\r\n</tsRequest>';
var config = {
method: 'post',
url: 'https://url.uni.edu/api/3.13/auth/signin',
headers: {
'Content-Type': 'text/plain'
},
data : data
};
I try to create the global token variable (this is where I'm struggling)...
const token= axios(config)
.then((response) => {
console.log(response.data.credentials.token);
}).catch((err) => {
console.log(err);
});
console.log(token)
I have a functioning app.get request where instead of manually providing the token, I want to use the const token...
app.get('/gql', async (req, res) => {
var someObject = {
'method': 'POST',
'url': 'https://diffurl.uni.edu/api/metadata/graphql',
'headers': {
'X-Some-Auth': token,
'Content-Type': 'application/json'
},
The Current Results
What I have for the var data = and the var config = and the axios(config) all work to return the token via console.log, but I have 2 issues using axios.
The Axios Issues
In my hopes of creating a global token variable, I only understand how to get a console.log result instead of returning a 'useful data object'.
In just about every piece of documentation or help found, the example uses console.log, which is not a practical example for learners to move beyond just returning the data in their console.
What do I need to provide in axios to create a global token object in addition to or instead of console.log?
I realize 1. is my current blocker, but if I run my app, I get the following:
Promise { <pending> }
Express server running on port 1234
abc123 [the console.logged token via axios]
I'm not sure what the Promise { <pending> } means, how do I fix that?
Beyond The Axios Issues
If the axios problem is fixed, am I passing the const token correctly into my app.get... var someObject... headers?
Thank you for any help you can provide.
This is what Axios interceptors are for.
You can create an Axios instance with an interceptor that waits for the token request to complete before adding the token to the outgoing request.
A response interceptor can be added to handle 401 statuses and trigger a token renewal.
const data = "<tsRequest>...</tsRequest>";
let renew = true;
let getTokenPromise;
const renewToken = () => {
if (renew) {
renew = false; // prevent multiple renewal requests
getTokenPromise = axios
.post("https://url.uni.edu/api/3.13/auth/signin", data, {
headers: {
"content-type": "text/plain", // are you sure it's not text/xml?
},
})
.then((res) => res.data.credentials.token);
}
return getTokenPromise;
};
const client = axios.create();
// Request interceptor to add token
client.interceptors.request.use(async (config) => ({
...config,
headers: {
"X-Some-Auth": await renewToken(),
...config.headers,
},
}));
// Response interceptor to handle expiry
client.interceptors.response.use(
(res) => res,
(error) => {
if (error.response?.status === 401) {
// Auth expired, renew and try again
renew = true;
return client(error.config);
}
return Promise.reject(error);
}
);
// if putting this in a module...
// export default client;
The first time you try to make a request, the token will be retrieved. After that, it will continue to use the last value until it expires.
if you want to create a to send the token with every request in axios you should create a custom axios instance or change the global axios default
you will find the way to do it here, about promise problem you need to resolve it using .then
this how i think you should do it
// first create axios instance
// you can set config defaults while creating by passing config object see the docs
const instance = axios.create();
// then get the token from API
axios(config).then(response=>{
instance.defaults.headers.common["header you want to set"]=response.data.credentials.token
});
// then use the instance to make any request you want that should have the token
I'm struggling with AXIOS: it seems that my post request is not using my Cookie.
First of all, I'm creating an Axios Instance as following:
const api = axios.create({
baseURL: 'http://mylocalserver:myport/api/',
header: {
'Content-type' : 'application/json',
},
withCredentials: true,
responseType: 'json'
});
The API I'm trying to interact with is requiring a password, thus I'm defining a variable containing my password:
const password = 'mybeautifulpassword';
First, I need to post a request to create a session, and get the cookie:
const createSession = async() => {
const response = await api.post('session', { password: password});
return response.headers['set-cookie'];
}
Now, by using the returned cookie (stored in cookieAuth variable), I can interact with the API.
I know there is an endpoint allowing me to retrieve informations:
const readInfo = async(cookieAuth) => {
return await api.get('endpoint/a', {
headers: {
Cookie: cookieAuth,
}
})
}
This is working properly.
It's another story when I want to launch a post request.
const createInfo = async(cookieAuth, infoName) => {
try {
const data = JSON.stringify({
name: infoName
})
return await api.post('endpoint/a', {
headers: {
Cookie: cookieAuth,
},
data: data,
})
} catch (error) {
console.log(error);
}
};
When I launch the createInfo method, I got a 401 status (Unauthorized). It looks like Axios is not using my cookieAuth for the post request...
If I'm using Postman to make the same request, it works...
What am I doing wrong in this code? Thanks a lot for your help
I finally found my mistake.
As written in the Axios Doc ( https://axios-http.com/docs/instance )
The specified config will be merged with the instance config.
after creating the instance, I must follow the following structure to perform a post requests:
axios#post(url[, data[, config]])
My requests is working now :
await api.post('endpoint/a', {data: data}, {
headers: {
'Cookie': cookiesAuth
}
});
So I'm sending some formdata, including images to my backend. To obfuscate/secure my backend even more - I'm learning that it's good practice to take advantage of the NextJS api (send calls from client to NextJS server/api, NextJS api acts as a middleman and sends data to backend api). I'm also using Auth0 - and the most secure way to get tokens is via the NextJS api itself.
I have no issues reading the data on my backend when I make an api call directly from client to backend. However, I'm having issues actually getting the data (primarily the images/files) OUT of the request on my NextJS api for repackaging and sending to my actual backend. I can't use FormData within the NextJS api either, so I'm just confused all around.
Client submit function:
const handleSubmit = async (e) => {
e.preventDefault();
const formData = new FormData();
formData.append("title", brand.name);
formData.append("slug", brand.slug);
formData.append("bio", brand.bio);
formData.append("logo", brand.logo[0]);
const response = await fetch("/api/brands", {
method: "post",
body: formData,
});
});
NextJS api code (does not work - I am getting an access token perfectly, it's just the sending of the formdata/files I'm stuck on)
import { getAccessToken, withApiAuthRequired } from "#auth0/nextjs-auth0";
export default withApiAuthRequired(async function products(req, res) {
const { accessToken } = await getAccessToken(req, res, {});
const response = await fetch("http://localhost:5000/brands", {
method: "post",
headers: {
Authorization: `Bearer ${accessToken}`,
},
body: {
title: req.body.title,
slug: req.body.slug,
bio: req.body.bio,
logo: req.file,
},
});
const products = await response.json();
res.status(200);
});
You might be missing the "Content-Type: multipart/form-data" on the 2nd API call that you make. On the client side it's inferred from the FormData object, but on the server side you have to specify it manually. Altough, I couldn't find a way to do that on the server. This could indicate that the use case is wrong, I think making another request to your own server is a no-no. Next.js is meant to use this function called "withApiAuthRequired" as a wrapper, from which you call your services, or business logic. There is no need to make a second HTTP Request here.
I am using react(frontEnd) with nodejs (backend), I am trying to send post request from client to sever. .
Client Side
Here below I sending the request to server, by using axions.
I tried without axions simply calling fetch instead.I tired with adding localhost:5000 and without but I it still not working.
FYI , all the data that I am sending are valid and there are as requested.
Server
Here I am trying to handle my request and at least print it to console to verify that my request is as passed valid
result of prints!!!
could you please advise regarding the above ?
After adding body-parser:
currently I am getting a undefined object, could you please advise?
Try This way
const data = {
name: this.state.additionalCost
};
axios
.post(
'/api/processData',
data,
{ headers: { 'Content-Type': 'application/json' } }
)
.then(function(result) {
console.log(result);
});
And use body-parser in express app
import express from 'express';
import bodyParser from 'body-parser';
app.use(bodyParser.json());
Set content type in header and check
axios.post('url', data, {
headers: {
'Content-Type': 'application/json',
}
}
You don't need to JSON.stringify your data from the react axios request.
Here's an example:
const user = {
name: this.state.name
};
axios.post(`https://jsonplaceholder.typicode.com/users`, { user })
.then(res => {
console.log(res);
console.log(res.data);
}
)
For more read Using Axios with React.