Making an http request using NodeJS and access the returned cookies - node.js

I am querying a remote API using NodeJS. I am currently using Axios to make the request, but I am willing to use another package if required.
Using NodeJS, I make a request to a remote API.
Axios.post("http://remote.api/getCookie")
.then(value => {
console.log(value);
});
The API returns a number of cookies (this can be seen in the spec, and when I test it in a browser). How can I access these cookies from the value returned by Axios.

Just get them from the Set-Cookie header:
Axios.post("http://<url>").then(response => {
const cookies = response.headers["set-cookie"];
// do whatever you want
}
You can then parse the header by yourself or use a library like cookie or set-cookie-parser

Related

Setting a cookie from a previous request when using axios in a Lambda function

I am using Axios in my NodeJs application to do HTTP requests.
I am logging in using a post request that does not require a cookie set in the header.
const instance = axios.create({ baseURL: 'https://some_url.com' , withCredentials: true});
const response = await instance.post('auth/login', data);
This returns a set-cookie in its header that I need to use in all subsequent API call. This is code I have tried for this.
const getResponse = await instance.get('/getStuff?$top=10', { withCredentials: true });
This always returns a "Not logged in error". I do not have access to the server, but I am assuming this is because my get request did not send the cookie in its header.
Running all of this in a lambda, not sure if that makes a difference.
Question: How do I get the cookie from my first post request and use it in my get request?
The withCredentials option is for the browser version of axios, and relies on browser for storing the cookies for your current site.
Since you are using it in Node, you will have to handle the storage yourself.
TL;DR
After the login request, save the cookie somewhere. Before sending other requests, make sure you include that cookie.
To read the cookie, check response.headers object, which should have a set-cookie header (which is all cookies really are - headers with a bit of special convention that has evolved into some sort of standard).
To include the cookie in your HTTP request, set a cookie header.
General example
You could also look for some "cookie-handling" libraries if you need something better than "save this one simple cookie I know I'll be getting".
// 1. Get your axios instance ready
function createAxios() {
const axios = require('axios');
return axios.create({withCredentials: true});
}
const axiosInstance = createAxios();
// 2. Make sure you save the cookie after login.
// I'm using an object so that the reference to the cookie is always the same.
const cookieJar = {
myCookies: undefined,
};
async function login() {
const response = await axiosInstance.post('http://localhost:3003/auth', {});
cookieJar.myCookies = response.headers['set-cookie'];
}
// 3. Add the saved cookie to the request.
async function request() {
// read the cookie and set it in the headers
const response = await axiosInstance.get('http://localhost:3003',
{
headers: {
cookie: cookieJar.myCookies,
},
});
console.log(response.status);
}
login()
.then(() => request());
You could also use axios.defaults to enforce the cookie on all requests once you get it:
async function login() {
const response = await axios.post('http://localhost:3003/auth', {});
axios.defaults.headers.cookie = response.headers['set-cookie']
}
async function request() {
const response = await axios.get('http://localhost:3003');
}
As long as you can guarantee that you call login before request, you will be fine.
You can also explore other axios features, such as interceptors. This may help with keeping all "axios config"-related code in one place (instead of fiddling with defaults in your login function or tweaking cookies in both login and request).
Lambda
AWS Lambda can potentially spawn a new instance for every request it gets, so you might need to pay attention to some instance lifecycle details.
Your options are:
Do Nothing: You don't care about sending a "login request" for every lambda run. It doesn't affect your response time much, and the other api doesn't mind you sending multiple login requests. Also, the other api has no problem with you having potentially multiple simultaneous cookies (e.g. if 10 lambda instances login at the same time).
Cache within lambda instance: You have a single lambda instance that gets used every once in a while, but generally you don't have more than one instance running at any time. You only want to cache the cookie for performance reasons. If multiple lambda instances are running, they will each get a cookie. Beware the other api not allowing multiple logins.
If this is what you need, make sure you put the axios config into a separate module and export a configured instance. It will be cached between runs of that one lambda instance. This option goes well with interceptors usage.
const instance = axios.create({...});
instance.interceptors.response.use(() => {}); /* persist the cookie */
instance.interceptors.request.use(() => {}); /* set the cookie if you have one */
export default instance;
Cache between lambda instances: This is slightly more complicated. You will want to cache the cookie externally. You could store it in a database (key-value store, relational, document-oriented - doesn't matter) or you could try using shared disk space (I believe lambda instances share some directories like /tmp, but not 100% sure).
You might have to handle the case where your lambda gets hit by multiple requests at the same time and they all think they don't have the cookie, so they all attempt to login at the same time. Basically, the usual distributed systems / caching problems.

Nuxt - Axios requests on server side not sending referer

The story
My backend app provides SEO information for my sites pages. One of this informations are OpenGraph meta tags, such as og:type and og:url.
og:url value is given by the API through the HTTP "Referer" header.
What I'm doing now
I'm using Axios module to make my requests.
Through asyncData function in my pages I can get the req variable and it's headers.referer property, which is what I want, like this:
// page.vue
async asyncData({ app, req }) {
app.$axios.setHeader('Referer', req.headers.referer);
}
The problem
If I am at the index page, let's say, then I click in a link to a dynamic page I got an error, for req is not available on asyncData function while navigating, I suppose.
The question
How can I dynamically get my requests referers to send it with Axios request for both client-side and server-side requests?
Info about the versions:
nuxt: 1.4.2
#nuxtjs/axios: 5.3.1
You can do something like this:
async asyncData({ app, req }) {
const referrer = process.client ? window.document.referrer : req.headers.referer
app.$axios.setHeader('Referer', referrer)
}

Postman Requests Receive a HTTP 401 Status Code

I am working on creating a Node.js REST API, using the Express module, that redirects HTTP GET and PUT requests to another server. However, when running test queries in Postman, I always get HTTP 401 Unauthorized responses. Yet, when I try the same on query on the Chrome browser I get a successful response (HTTP 302). I read through some documentation on the HTTP request/response cycle and authorization. The server I am redirecting to uses HTTP Basic authentication. In my code I am redirecting the API call to my application server using the res.redirect(server) method. In my Postman request I am setting the username/password in Authorization tab for my request. I know this is gets encoded using base64, but I am guessing this isn't being passed on the redirect when done through Postman.
The following code snippets show what I've created thus far.
This is the Express route I created for GET requests
app.get('/companyrecords/:name', function(req, res) {
var credentials = Buffer.from("username:password").toString('base64');
console.log(req);
var requestURL = helperFunctions.createURL(req);
res.redirect(requestURL);
});
I define a function called createURL inside a file called helperFunctions. The purpose of this function is set up the URL to which requests will be directed to. Here is the code for that function.
module.exports.createURL = function (requestURL) {
var pathname = requestURL._parsedUrl.pathname;
var tablename = pathname.split("/")[1];
var filter = `?&filter=name=\'${requestURL.params.hostname}\'`;
var fullPath = BASE_URL + tablename.concat('/') + filter;
console.log(fullPath);
return fullPath;
}
Where BASE_URL is a constant defined in the following form:
http://hostname:port/path/to/resource/
Is this something I need to change in my code to support redirects through Postman or is there a setting in Postman that I need to change so that my queries can execute successfully.
Unfortunately you can't tell Postman not to do what was arguably the correct thing.
Effectively clients should be removing authorisation headers on a redirect. This is to prevent a man-in-the-middle from sticking a 302 in and collecting all your usernames and passwords on their own server. However, as you've noticed, a lot of clients do not behave perfectly (and have since maintained this behaviour for legacy reasons).
As discussed here however you do have some options:
Allow a secondary way of authorising using a query string: res.redirect(302, 'http://appServer:5001/?auth=auth') however this is not great because query strings are often logged without redacting
Act as a proxy and pipe the authenticated request yourself: http.request(authedRequest).on('response', (response) => response.pipe(res))
Respond with a 200 and the link for your client to then follow.

How to Get Current User in Backend with Firebase in Node.js?

I am so confused,
all the Firebase authentication tutorial online are teaching how to login in frontend,
of course you can get the token and send it to server for verification if its a post request,
but what about normal get request like a page request? I have installed firebase-admin already but i didnt find any method for getting current user........
i am using node and express
for example
app.get('/', function(req, res) {
const idToken = (where can i get the token??)
console.log(idToken);
res.render('index.ejs');
});
You still have to arrange for the auth token to be sent in the HTTP request. You can do that with a header in the request. Sample code showing exactly this case can be found in the official samples. This will work for any HTTP method, and is a lot better than trying to use a POST body.
The sample uses the Authorization header to transmit the token and verifyIdToken() to make sure it's valid.

Connect NodeJS as client to third party service that uses session data

I am developing a website in Node.JS / Express, and have until now used JWTs to store authentication data.
To summarize, I have an AngularJS app which calls a REST service on Node, and for authentication the user POSTs username and data to the server and gets a JWT containing the username and expiration, which then gets sent along with every request which requires authentication.
Now, though, I need to be able to connect to a third party service (which is a REST service that runs on Delphi) which uses sessions to save authentication data instead.
Using Fiddler, I can see that the service, when used in another implementation (third party) responds with JSON authentication data. In all subsequent requests, the client sends a cookie called dsessionid, although it doesn't appear in the "response cookies" in the previous response.
My question is: how do I take that dsessionid cookie in my NodeJS app and put it in my JWT so I can send it to my actual client?
I managed to solve my problem by getting the session ID in the "Pragma" header of the response (I don't know if the header is something "default" for Delphi applications or if it was specific to this application, I had to look through Fiddler entries to find out what header had the data) and then using a custom cookie jar with the request module to put the session ID in the cookies of subsequent requests.
const request = require('request-promise-native')
return request.get({
url: 'http://example.com:20202/auth',
resolveWithFullResponse: true
})
.then(res => {
return res.headers['pragma']
})
.then(sid => {
let j = request.jar()
j.setCookie(request.cookie('sessionid=' + sid), 'http://example.com')
return request.get({
url:'http://example.com:20202/fetchData',
resolveWithFullResponse: true,
jar: j
})
Hope this helps somebody.

Resources