Node Axios Create Global Token Variable for Use in Separate Variable Header - node.js

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

Related

bearer token in Twilio webhook

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

Notion API OAuth Not working `invalid client`

I've tried setting up Notion OAuth and everything works fine on postman but on my application it's not.
I've tried many ways and this is the last implementation I've did so far.
router
.get("/notion/authorize", async (req : Request, res: Response) => {
let redirectURL = `${process.env.NOTION_AUTH_URL}?owner=user&client_id=${process.env.NOTION_CLIENT_ID}&response_type=code&redirect_uri=${encodeURI(process.env.NOTION_REDIRECT_URI)}`
res.redirect(redirectURL)
})
.get("/notion/callback", async (req: Request<any,any, any, {code : string } >, res: Response) => {
try {
const {code} = req.query;
console.log(code)
if(!code) {
throw new Error("Code is required from notion")
}
const response = await axios.post('https://api.notion.com/v1/oauth/token', {
data:JSON.stringify({
"grant_type":"authorization_code",
"code":code,
"redirect_uri": "http://localhost:9000/notion/callback"
}),
headers: {
"Authorization": `Basic ${Buffer.from(`${process.env.NOTION_CLIENT_ID}:${process.env.NOTION_CLIENT_SECRET}`).toString('base64')}`,
"Content-Type": "application/json",
}
})
const {access_token, bot_id, workspace_id, workspace_name} =response.data;
//.. more code
}catch(err) {
if(axios.isAxiosError(err)) {
console.log(err.response.data, err.response.status)
}
return res.status(400).json({message: `Failed to register user ${err}`})
}
})
Stil I get this as error { error: 'invalid_client' } 401
Also yes, checked the keys and redirect URI as well.
Please help me with this :)
It seems like your header is wrong. Check if the field authorization gives the same value as the one you use in postman.
Other thing is your post request. I think you're messing up something. Axios can take one single object when using the request method or 3 parameters (url, data, config) when using the post method (Axios Documentation). In your code, the data and the headers are together and should be apart in different objects.

Nodejs - Axios not using Cookie for post request

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

Add new fields to context variable in strapi backend for user management

I am using strapi as backend and react in the front-end. So the use case is that the user will signup and that signup will be done using auth0. I have defined some roles for the users signing up as shown on auth0
Roles based on plan taken by user
const _ = require("lodash");
const axios = require("axios");
const jwt = require("../jwt");
module.exports = async (ctx, next) => {
let role;
if (ctx.state.user) {
// request is already authenticated in a different way
return next();
}
try {
const tokenInfo = await axios({ method: "post",
url: `${process.env.AUTH0_URL}/userinfo`,
headers: { Authorization: ctx.request.header.authorization,
},
});
let user_id = tokenInfo.data.sub;
var config = { method: "get",
url: `${process.env.AUTH0_URL}/api/v2/users/${user_id}/roles`,
headers: {Authorization: `Bearer ${jwt.jwtSecret}`,
},
};
axios(config).then(function (response) {
ctx.state.roles = response.data[0].name; // This part does not work in the next policy as ctx.state.role gives undefined in route specific policy
}).catch(function (error) {
console.log(error);
});
// console.log(tokenInfo.data, "tokeninfo");
if (tokenInfo && tokenInfo.data) {
return await next();
}
} catch (err) {
console.log(err.message);
return handleErrors(ctx, err, "unauthorized");
}
Currently these will be managed here only. Now I have a collection which has some research articles which can only be accessed depending upon the plan user has been assigned. In order to protect the route and strapi access I have installed user-permissions plugin in strapi and managing userinfo using a global policy as shown
Project Structure
. So here is the code through which I am checking the user info on every route
Now there are two ways in which I tried solving my problem. First I read the tokenInfo data from userInfo route but unfortunately auth0 is not returning roles assigned. It is only returning standard data like
"name": "ansh5#gmail.com",
"nickname": "ansh5",
"picture": "https://s.gravatar.com/avatar/6fdb83f10321dd7712ac2457b11ea34e?
s=480&r=pg&d=https%3A%2F%2Fcdn.auth0.com%2Favatars%2Fan.png",
"updated_at": "2021-07-19T08:03:50.461Z",
"user_id": "auth0|60ec0b3721224b0078ac95f4",
So in order to get user role I used the other API and configured it with my auth0 account.
${process.env.AUTH0_URL}/api/v2/users/${user_id}/roles
I am getting the correct response but when I am doing this assignment.
ctx.state.roles = response.data[0].name;
I am getting undefined in my ctx.state.roles in my route specific policy. Does anybody have idea how we manage strapi and auth0 together.
Yes, it's because the axios calls are asynchronous in nature. So as per your code, axios will try to get the user information over a network call, but strapi will not really wait for the response. Instead it will just move forward to the next policy, hence resulting in an undefined user role. To fix this, you need to await for the api response from axios. Try the code below:
const axios = require("axios");
const jwt = require("../jwt");
module.exports = async (ctx, next) => {
let role;
if (ctx.state.user) {
// request is already authenticated in a different way
return next();
}
try {
const tokenInfo = await axios({
method: "post",
url: `${process.env.AUTH0_URL}/userinfo`,
headers: {
Authorization: ctx.request.header.authorization,
},
});
let user_id = tokenInfo.data.sub;
var config = {
method: "get",
url: `${process.env.AUTH0_URL}/api/v2/users/${user_id}/roles`,
headers: {
Authorization: `Bearer ${jwt.jwtSecret}`,
},
};
const resp = await axios(config);
ctx.state.roles = response.data[0].name;
console.log(ctx.state.roles);
// console.log(tokenInfo.data, "tokeninfo");
if (tokenInfo && tokenInfo.data) {
return await next();
}
} catch (err) {
console.log(err.message);
return handleErrors(ctx, err, "unauthorized");
}
}

Axios - Prevent sending JWT token on external api calls

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!

Resources