API Server giving 401 error after login - javascript

I have successfully logged in to the API Server using following code in meteorjs
var request = Npm.require('request');
request('http://api-server-link-here',
{
'auth' : {
'user': 'username',
'pass': 'password',
'sendImmediately': false
}
}
, function (error, response, body) {
if (!error && response.statusCode == 200) {
console.log(response);
}
But after this login when i go for using search query using code below. I get Http Status 401 error.
var request = Npm.require('request');
request("http://search-query-link-here",
{
//search query parameters are here
},
function(error,response,body){
console.log(response);
});
Can anybody please give me pointers of why this issue is happening. Or if this is possible that i get a working example here?
One more thing that needs to be told here is that I'm doing login with the help of digest authentication.

Obviously, it's kind of hard to provide you with a working example for an unknown API.
But let's just try to sort it out. Logically, when you send your search query, you are supposed to identify yourself. Most of the public API servers use either tokens (most probably) or session cookies in order to authorize access to a resource. So, whenever you do your second (search) request, you have either provide a token or send a cookie you are getting from the first (login) request.
Long story short, verify which mechanism is being used by the API server.
if it's tokens: check the response body from the login request; most probably there will be an access token you'd send then in the Authorization header of your API calls: headers: {'Authorization': 'Bearer ...'} in your request options;
if it's sessions: make sure you have the cookie jar enabled on login and you it for subsequent requests: https://github.com/mikeal/request#requestjar

Related

Get authorization token from headers into fetch reactj

I am using fetch in my react project to fetch data from an API which is authenticated using a token and my login end-point in the postman return the token in authorization header, you can see
and this's my login funtion in reactjs project
async login(dataLogin) {
const response = await fetch(`${API_URL}/login`, {
method: "post",
headers: {
"Content-Type": "application/json"
},
body: dataLogin
});
const data = await response
console.log(response.headers);
console.log(response.headers.Authorization);
console.log(response.headers.get('Authorization'));
return data;}
you can see that response.headers.authorization return undefined and
response.headers.get('Authorization') return null.
and you can see in my browsers' Network panel
please anyone know how to get the authorization token from the headers?
When you are trying to login using API, then you should receive data i.e. Authorization token or anything else in the response of call.
Check what is the response you're getting when you called an API, it should probably be like
response.data
First you need to check the same in Postman.
To access value of response header server must return header name in Access-Control-Expose-Headers header. Without it Authorization is inaccessible in browser.
response.headers.get('Authorization')
Edit:
Since you are getting null, consider that:
The Authorization header is usually, but not always, sent after the
user agent first attempts to request a protected resource without
credentials.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization
Therefore, instead of using postman, in order to see the response header, use the browsers' Network panel.

axios : How exactly to preserve session after successful authorization and send with subsequent request - while testing without browser

In this test case am sending an axios post request with userId and password to ExpressJS server running with passportjs local. Server respond with status code 200, and send appropriate header with set-cookie.
I need subsequent request to be treated as authorized request, for that tried following options, but none seems to be working. It getting rejected with status code 401.
First call with userid and password, responded with status 200
const userDoc = {
userId: 'test-user-1',
userName: 'Test User 1',
emailId: 'test.user.1#abc.xom',
password: 'test-password'
} ;
let resp
resp = await axios({method : 'post', url : 'http://localhost:4040/auth/local', data : {userId: userDoc.userId, password: userDoc.password },withCredentials: true })
following options are used to send next request
send cookies received as part of 1st request
const headers = { headers : {Cookie: resp.headers['set-cookie'][0] } };
send header as it is received as part of 1st request
const headers = { headers : resp.headers};
send withCredentials: true along with above headers.
Second call is made with either of above option
resp = await axios({method : 'post', url : 'http://localhost:4040/v1/master/account', data : accountDoc , headers, withCredentials: true})
used httpAgent, keepAlive with axios instance
const axios = require('axios')
const http = require("http")
const httpAgent = new http.Agent({keepAlive : true , timeout :1000})
const instance = axios.create({httpAgent})
const resp1 = await instance({method : 'post', url : 'http://localhost:4040/auth/local', data : {userId: userDoc.userId, password: userDoc.password, } , withCredentials: true })
const resp2 = await instance({method : 'post', url : 'http://localhost:4040/v1/master/account', data : accountDoc , withCredentials: true })
Rejected with status code 401
-- Error: Request failed with status code 401
at createError (/home/Projects/FinAccounts2003/node_modules/axios/lib/core/createError.js:16:15)
at settle (/home/Projects/FinAccounts2003/node_modules/axios/lib/core/settle.js:17:12)
at IncomingMessage.handleStreamEnd (/home/Projects/FinAccounts2003/node_modules/axios/lib/adapters/http.js:269:11)
at IncomingMessage.emit (events.js:412:35)
at endReadableNT (internal/streams/readable.js:1334:12)
at processTicksAndRejections (internal/process/task_queues.js:82:21)
Server code is standard passport-js local code, which working well with browser.
It may be duplicate of some of the questions, solutions given are 1) withCredentials: true, already tried above 2) Authorization: Bearer ${token} - not applicable in this case, in passport js, cookie is directly set, and not getting token.
One solution that worked for me was using the modules tough-cookie and axios-cookiejar-support. I combined them in a persistent-client.js file, and then I was able to maintain the session between requests (commonJS):
const axios = require('axios').default;
const { CookieJar } = require('tough-cookie');
const { wrapper } = require('axios-cookiejar-support');
module.exports = function () {
const jar = new CookieJar();
const client = wrapper(axios.create({ jar }));
return client;
}
There are two different ways to send the session authorization token from the server to the client (web browser)
Via (HttpOnly) response headers.
Via the response body.
And there are two different ways to authorize client requests (send the session token from the web browser to the server.)
A. Automatic: HttpOnly headers
B. Manual: Authorization: Bearer [TOKEN]
Usually method 1 is used with method A, and method 2 is used with method B. I think you are mixing them up.
If the server is using Set-Cookie to send the session token, then I think the browser automatically sends the session token automatically on all future requests (to the same domain).
Can you confirm what the actual contents of the set-cookie header are from the server? Note you will probably not be able to check this via JS if these are HttpOnly cookies; inspect the dev console "Network" tab. You can also check to see if any new cookies were set from the "Application" tab.
If the client does actually need to manually send the token via headers, the header needs to fit a specific Authorization cookie format. (Which you are not doing. You are simply echoing the headers received from the server.)
See my response to a similar question.
I don't believe you should be using any third party packages for this, especially not if they're directly accessing the cookies using javascript (which is an XSS security vulnerability). Cookies should be set using secure and http-only and never be accessed using Document.cookie directly.
Make sure that passport is actually setting your cookie and that you're correctly sending back the cookie on the login. Verify that it's been set in your browser.
Make sure that you have CORS enabled in express, that you've specified the domain you're making requests from and that you've enabled credentials in CORS.
Make sure that you're using withCredentials on your axios requests.
Make sure that you've set the cookie using the correct domain and path.

Auth refresh token not working when the orgin request is a POST method

I have a js client (vuejs) and a backend using DRF both in local.
I use this package to generate the token : https://github.com/davesque/django-rest-framework-simplejwt
I use this package https://www.npmjs.com/package/axios-auth-refresh to handle refresh token logic.
The main goal is to intercept a request when it return a 401 response, perform a refresh token request and then resolve the orginal request with the new token.
It works when the original request is a GET request but not when it is a POST request.
When using a POST request :
The orgin request fall in 401 when the token expire then the interceptor occur but the server respond with 405 method not allowed:
-https://imgur.com/C1tchvb
the method from the request from the interceptor does not match the method in the code shown above (line 3 & 4) : as you can see the server receive the payload from the origin request as method of the request :
-https://imgur.com/nlAknMi
I found this post : App Script sends 405 response when trying to send a POST request
i try to change the headers as advised but it did not work
How is the payload from the orginal resquest becoming the method of the interceptor when the origin request is a Post request with a payload ?
Here the code from the javascript client :
const refreshAuthLogic = failedRequest => axios(
{
method: 'post',
url: 'auth/refresh',
data: { refresh: store.state.token.refresh }
}).then(tokenRefreshResponse => {
store.dispatch('refreshToken', tokenRefreshResponse.data)
return Promise.resolve()
})
const instance = axios.create({
baseURL: '/api/'
})
instance.interceptors.request.use(config => {
config.headers.Authorization = `Bearer ${store.state.token.access}`
return config
})
createAuthRefreshInterceptor(instance, refreshAuthLogic)
EDIT
I manage to get it work but i don't really understand:
the problem is related to DJANGO/ DRF and not axios
it seems that when a POST request is done and fail ( here with 401) the server keeped the data.
Here the part i can't explain :
when the request of the interceptor (to refresh token) hit the server, it messes with the data of previous request.
I had to add a middleware in django to clear the body when the request fails with 401 and it worked for me. But it is not a proper solution i guess.
Unfortunately the lib is loosely mantained and it's flawed in some aspects.
Eg: concurrent requests are not correctly queued when the request is sent with and invalid token but the response arrives when a new token is already issued.
As is, if you look at the lib source, you'll find in the very first lines:
/** #type {Object} */
const defaults = {
/** #type {Number[]} */
statusCodes: [
401 // Unauthorized
]
};
This means that only 401 code is managed and the statusCodes are not exported so them remains private.
If you want to continue to use this library you can fork it in order to change what does not fit with your stack or simply copy the source, edit it and use it as a local service.

Node.js - How to send sessionID to GET method in Express via request package? [duplicate]

I'm trying to use NodeJS to scrape a website that requires a login by POST.
Then once I'm logged in I can access a separate webpage by GET.
The first problem right now is logging in. I've tried to use request to POST the login information, but the response I get does not appear to be logged in.
exports.getstats = function (req, res) {
request.post({url : requesturl, form: lform}, function(err, response, body) {
res.writeHeader(200, {"Content-Type": "text/html"});
res.write(body);
res.end();
});
};
Here I'm just forwarding the page I get back, but the page I get back still shows the login form, and if I try to access another page it says I'm not logged in.
I think I need to maintain the client side session and cookie data, but I can find no resources to help me understand how to do that.
As a followup I ended up using zombiejs to get the functionality I needed
You need to make a cookie jar and use the same jar for all related requests.
var cookieJar = request.jar();
request.post({url : requesturl, jar: cookieJar, form: lform}, ...
That should in theory allow you to scrape pages with GET as a logged-in user, but only once you get the actual login code working. Based on your description of the response to your login POST, that may not be actually working correctly yet, so the cookie jar won't help until you fix the problems in your login code first.
The request.jar(); didn't work for me. So I am using the headers response to make another request like this:
request.post({
url: 'https://exampleurl.com/login',
form: {"login":"xxxx", "password":"xxxx"}
}, function(error, response, body){
request.get({
url:"https://exampleurl.com/logged",
header: response.headers
},function(error, response, body){
// The full html of the authenticated page
console.log(body);
});
});
Actualy this way is working fine. =D
Request manages cookies between requests if you enable it:
Cookies are disabled by default (else, they would be used in
subsequent requests). To enable cookies, set jar to true (either in
defaults or options).
const request = request.defaults({jar: true})
request('http://www.google.com', function () {
request('http://images.google.com')
});

HTTP Basic Authentication GET request in AngularJS

I have one GET endpoint.
It has HTTP Basic Authentication enabled. I want to create a GET request to the given end point.
https://example.com/api GET
User Name :- admin
Password :- admin
My Code :-
$scope.listData = function() {
$http.get('https://example.com/api').then(function(response) {
$scope.items = response.data;
});
}
What is the recommended way to pass the authentication?
Second argument for the GET is the header part. For ex.
$http.get('www.google.com/someapi', {
headers: {'Authorization': 'Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=='}
}).then()..;
the recommended method is http-interceptors.
what interceptor do, you can assume its a hook which call on every api request and response, once you write it, it will automatically add token in every api request. below is the url you read the article.
Angular Authentication: Using the Http Client and Http Interceptors

Categories

Resources