Reputation: 1932
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?
Upvotes: 11
Views: 14764
Reputation: 4079
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.
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
).
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.
Upvotes: 22