Postman - How to use pm.sendRequest without any cookies? - cookies

In my Postman collection, I have a pre-request script that ensures I have a valid JWT token available for authentication. It looks similar to the following (I have removed the logic of checking expiration and only fetching a new token if needed):
function get_and_set_jwt() {
let base_url = pm.environment.get("BASE_URL")
pm.sendRequest({
url: base_url + '/api/auth/',
method: 'POST',
header: {
'content-type': 'application/json',
'cookie': ''
},
body: {
mode: 'raw',
raw: JSON.stringify({ email: pm.environment.get("USER_EMAIL_ADDRESS"), password: pm.environment.get("USER_PASSWORD") })
}
}, function (err, res) {
let jwt = res.json().token
postman.setEnvironmentVariable("JWT", jwt)
});
}
get_and_set_jwt();
I am attempting to set 'cookie': '' so that the request from this script will be made with no cookies. The backend I am working with sets a session cookie in addition to returning the JWT, but I want to force all future requests (when I need to renew the JWT) to not include that session information.
Unfortunately, if I check the Postman console, I see that the requests are still being sent with the cookie header, and the session cookie that was set by the earlier response. I have even tried overriding it by setting 'cookie': 'sessionid=""', but that just yields a request that includes two session ids in the cookie header (it looks like sessionid=""; sessionid=fasdflkjawew123sdf123;)
How can I send a request with pm.sendRequest with either a completely blank cookie header, or without the header at all?

Related

Postman access refresh_token?

I configured Postman to use the authorization code flow. Problem is our tokens expiry pretty fast and I need to re-run the flow every time it expires. So I was thinking to implement a refresh_token flow in the pre-requests script (unless there is a Postman-native way to do it).
Now my question is where can I find the refresh_token? Is there any way to access it or is it 'thrown away' and only the access_token is used?
Add the following code to the Collection Pre-request Script. (Edit it to your own url and body.)
// Set refresh and access tokens
const loginRequest = {
url: pm.environment.get("mainUrl") + "/authenticate/login", //The url that the token returns
method: 'POST',
header: {
'content-type': 'application/json',
'Accept': "*/*"
},
body: {
mode: 'raw',
raw: JSON.stringify({ //Your body
"username": pm.environment.get("username"),
"password": pm.environment.get("password")
})
}
};
pm.sendRequest(loginRequest, function (err, res) {
pm.environment.set("accessToken", res.json().accessToken); //The token returned in the response and the environment value to which the value will be sent
pm.environment.set("refreshToken", res.json().refreshToken);
});
This request runs before every request.
Finally, In the "Token" field in the "Authorization" tab of the requests, call the accessToken value from the environments.
{{accessToken}}
Each time the request runs, it will refresh the token value and use this value.

fetch() Not setting cookie despite `Set-Cookie` header

My backend-api written in Node and Express.js sets a cookie using res.cookie:
Router.post('/login', async (req, res) => {
const email = req.body.email;
const password = req.body.password;
try {
let result = await sqlite.login(email, password);
res.cookie('token', result, {
'maxAge': 3600 * 1000
});
res.send({
'token' : result
});
} catch (err) {
res.send(err);
}
});
I can make a request to this route, and I do notice the Set-Cookie header is set on the response object within Chrome developer tools:
Set-Cookie: token=[...]; Max-Age=3600; Path=/; Expires=Mon, 11 Jul 2022 14:47:08 GMT
However, document.cookie is never set by the browser. From my searching, most people say to specify the credentials field as same-origin. I have done this and it made no change. My cookie is NOT being set as HttpOnly, so I am unsure why it's being set by the browser.
Here is where I call the /login route:
async login(email, password) {
let response = await fetch(apiURL + '/login', {
'method' : 'POST',
'headers' : {
'Content-Type' : 'application/json',
'Accept' : 'application/json'
},
'credentials' : 'same-origin',
'body' : JSON.stringify({
'email' : email,
'password' : password
})
});
return await response.json();
}
A token is successfully returned in the response, but again document.cookie returns an empty string ''.
From searching this problem, most of the issues seem to suggest that same-origin should fix the issue but it is not the case for myself. Another thing of note is that httpOnly cookies won't show in the browser, but I know that the cookies I am sending are not HttpOnly.
I am using Google Chrome version 103.0.5060.114.
If I set credentials to include, I get a CORS error:
The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'.
I was able to get it working with the following changes:
When initializing npm package cors, specify some options:
app.use(cors({ credentials: true, origin: 'http://lvh.me:3001' }));
The origin must include the http:// prefix as well as the correct port. Once that was done, set credentials to include when calling fetch() and it should work fine.

postman sendRequest use authorization from collection

I can send a request in a Postman pre-request script as seen below. What I would like to do is use the same authentication as is set in the Collection so that if the Collection changes then my sendRequest follows suite.
pm.sendRequest({
url: 'http://some_url',
method: 'GET',
header: {
'content-type': 'application/json',
'authorization': 'Basic ' + auth
},
}, function (err, res) {
// do something
});
The reason I want to do this is that I want to share the collection with partners and customers and each of them may use a different authentication type. At the moment I have configured my collection to use basic authentication and have used variables for user name and password. If, for example, a partner switches the collection to use OAuth then they will need to also update all of my pre-request scripts to use OAuth.
If pm.sendRequest() was able to inherit the authentication just as each request in the collection can then the partner could make the change in one place.
This will work, assuming you're executing sendRequest after a request which had an authorization header as well:
pm.sendRequest({
url: 'http://some_url',
method: 'GET',
header: {
'content-type': 'application/json',
'authorization': request.headers["authorization"]
},
}, function (err, res) {
// do something
});
Information on the Request object can be found here.

Next.js not persisting cookies

I have a server-side rendered Next.js/express app that communicates with a Django API (cross-origin). I login a user like so:
const response = await fetch('localhost:8000/sign-in', {
method: 'POST',
credentials: 'include',
body: JSON.stringify({ email, password }),
headers: { 'Content-Type': 'application/json' },
});
const result = await response.json();
if (response.status === 200) {
Router.push('/account');
}
Django successfully logs in the user and returns set-cookie headers for the csrftoken and sessionid cookies, however, when I navigate to a different page (like in the above code when I Router.push), the cookies don't persist.
I assume this has something to do with server-side vs. client-side, but when cookies are set in the browser I expect them to persist regardless.
How can I get these cookies, once set, to persist across all pages on the client side?
It turns out that set-cookie is the old way of doing things. It's controlled by the browser, so it's obfuscated.
I ended up sending the csrftoken and sessionid back to the client in the JSON body, and saving them to localStorage using localStorage.setItem('sessionid', 'theSessionId') and localStorage.setItem('csrftoken', 'theCsrftoken').
Then when I need to make an authenticated request, I include them in the fetch headers:
const response = await fetch(`${API_HOST}/logout`, {
method: 'POST',
headers: {
'X-CSRFToken': localStorage.getItem('csrftoken'),
sessionid: localStorage.getItem('sessionid'),
},
});

Fetch API with Cookie

I am trying out the new Fetch API but is having trouble with Cookies. Specifically, after a successful login, there is a Cookie header in future requests, but Fetch seems to ignore that headers, and all my requests made with Fetch is unauthorized.
Is it because Fetch is still not ready or Fetch does not work with Cookies?
I build my app with Webpack. I also use Fetch in React Native, which does not have the same issue.
Fetch does not use cookie by default. To enable cookie, do this:
fetch(url, {
credentials: "same-origin"
}).then(...).catch(...);
In addition to #Khanetor's answer, for those who are working with cross-origin requests: credentials: 'include'
Sample JSON fetch request:
fetch(url, {
method: 'GET',
credentials: 'include'
})
.then((response) => response.json())
.then((json) => {
console.log('Gotcha');
}).catch((err) => {
console.log(err);
});
https://developer.mozilla.org/en-US/docs/Web/API/Request/credentials
Have just solved. Just two f. days of brutforce
For me the secret was in following:
I called POST /api/auth and see that cookies were successfully received.
Then calling GET /api/users/ with credentials: 'include' and got 401 unauth, because of no cookies were sent with the request.
The KEY is to set credentials: 'include' for the first /api/auth call too.
If you are reading this in 2019, credentials: "same-origin" is the default value.
fetch(url).then
Programmatically overwriting Cookie header in browser side won't work.
In fetch documentation, Note that some names are forbidden. is mentioned. And Cookie happens to be one of the forbidden header names, which cannot be modified programmatically. Take the following code for example:
Executed in the Chrome DevTools console of page https://httpbin.org/, Cookie: 'xxx=yyy' will be ignored, and the browser will always send the value of document.cookie as the cookie if there is one.
If executed on a different origin, no cookie is sent.
fetch('https://httpbin.org/cookies', {
headers: {
Cookie: 'xxx=yyy'
}
}).then(response => response.json())
.then(data => console.log(JSON.stringify(data, null, 2)));
P.S. You can create a sample cookie foo=bar by opening https://httpbin.org/cookies/set/foo/bar in the chrome browser.
See Forbidden header name for details.
Just adding to the correct answers here for .net webapi2 users.
If you are using cors because your client site is served from a different address as your webapi then you need to also include SupportsCredentials=true on the server side configuration.
// Access-Control-Allow-Origin
// https://learn.microsoft.com/en-us/aspnet/web-api/overview/security/enabling-cross-origin-requests-in-web-api
var cors = new EnableCorsAttribute(Settings.CORSSites,"*", "*");
cors.SupportsCredentials = true;
config.EnableCors(cors);
This works for me:
import Cookies from 'universal-cookie';
const cookies = new Cookies();
function headers(set_cookie=false) {
let headers = {
'Accept': 'application/json',
'Content-Type': 'application/json',
'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
};
if (set_cookie) {
headers['Authorization'] = "Bearer " + cookies.get('remember_user_token');
}
return headers;
}
Then build your call:
export function fetchTests(user_id) {
return function (dispatch) {
let data = {
method: 'POST',
credentials: 'same-origin',
mode: 'same-origin',
body: JSON.stringify({
user_id: user_id
}),
headers: headers(true)
};
return fetch('/api/v1/tests/listing/', data)
.then(response => response.json())
.then(json => dispatch(receiveTests(json)));
};
}
My issue was my cookie was set on a specific URL path (e.g., /auth), but I was fetching to a different path. I needed to set my cookie's path to /.
If it still doesn't work for you after fixing the credentials.
I also was using the :
credentials: "same-origin"
and it used to work, then it didn't anymore suddenly, after digging much I realized that I had change my website url to http://192.168.1.100 to test it in LAN, and that was the url which was being used to send the request, even though I was on http://localhost:3000.
So in conclusion, be sure that the domain of the page matches the domain of the fetch url.