I am using axios to make different GET and POST requests to a third-party API that requires a username and password login to access the data. I have tried several approaches to make this work but I keep getting this error in the console.
data: '<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">\n' +
'<html><head>\n' +
'<title>401 Unauthorized</title>\n' +
'</head><body>\n' +
'<h1>Unauthorized</h1>\n' +
'<p>This server could not verify that you\n' +
'are authorized to access the document\n' +
'requested. Either you supplied the wrong\n' +
'credentials (e.g., bad password), or your\n' +
"browser doesn't understand how to supply\n" +
'the credentials required.</p>\n' +
'</body></html>\n'
}
I have been using this approach to send the username and password with node.js
export const getCameraStream = (req, res) => {
let conn = createConnection(config);
let query = `SELECT * FROM cameras WHERE id = ${req.params.id}`
conn.connect();
conn.query(query, async (error, rows, _) => {
const camera = rows[0];
const username = camera.user;
const password = camera.pass;
if (error) {
return res.json({ "status": "failure", "error": error });
}
const result = await axios({
method: 'get',
url: <placeholder for api url>,
auth: {
username, password
}
})
console.log(result);
});
conn.end();
}
and then use this code on my React front-end
const getCameraStream = async () => {
const username = camera.user
const password = camera.pass
try {
const token = Buffer.from(`${username}:${password}`).toString('base64')
const res = await publicRequest.get(`camera/getCameraStream/${camera.id}`, {
headers: {
'content-type': 'multipart/x-mixed-replace; boundary=--myboundary',
'Authorization': `Basic ${token}`
},
auth: {
username, password
}
})
console.log(res)
} catch (error) {
console.error(error)
}
}
Using this approach, I am able to pass the username and password to the server and the responseUrl property is correct. However, my app crashes and I keep getting the same unauthorized error in the console. Could this be an issue with the fact that the browser is sending a preflight OPTIONS request or am I overlooking something with my authorization?
Related
I have a login form which is collect user email and password. Then I use JavaScript fetch to post data to express. then I use express validator check the inputs are correct. Then I send response res.status(200).redirect("/auth"); like this, but JavaScript is prevent the login page to redirect because in my external JavaScript I use e.preventDefault() function. But I want to redirect to next page. When I remove e.preventDefault() it stops the validation so I cant remove that. What should I do?
I'm using Node, Express Js, JSON file for storing Data, EJS Template with external JavaScript file. Aslo serving static JavaScript file too which is located in public/js/script.js file. Also using express-validator in middleware folder to validate the fields
Here is the express code:
export const loginsHandle = async (req, res) => {
const {
email,
password,
} = req.body;
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(422).json({
errors: errors.array(),
});
} else {
try {
var accountPP = new PP({
email: email,
password: password,
});
let addingData = JSON.parse(fs.readFileSync(accountDataFile, "utf-8"));
addingData.push(accountPP);
await fs.writeFileSync(accountDataFile, JSON.stringify(addingData));
res.status(200).redirect("/auth");
} catch (error) {
console.log(error);
res.status(200).send(error);
}
}
};
Here is external JavaScript :
const form = document.querySelector("form");
const emailInput = document.getElementById("email");
const passwordInput = document.getElementById("password");
const btn = document.getElementById("submit");
const forGot = document.getElementById("forgot");
const singBtn = document.getElementById("sign");
const footer = document.getElementById("menuFoot");
forGot.addEventListener("click", (e) => {
e.preventDefault();
});
singBtn.addEventListener("click", (e) => {
e.preventDefault();
});
footer.addEventListener("click", (e) => {
e.preventDefault();
});
form.onsubmit = sendLogin;
function sendLogin(e) {
e.preventDefault();
let formData = new FormData(form);
let Params = {
headers: {
"Content-Type": "application/json",
accept: "application/json",
},
body: JSON.stringify({
email: formData.get("email"),
password: formData.get("password"),
}),
method: "POST",
};
fetch("http://localhost:5001/login", Params)
.then((res) => {
return res.json();
})
.then((data) => {
if (data.errors) {
data.errors.forEach((err) => {
if (data.errors[0].param == "email") {
emailInput.style.borderColor = "red";
} else if (data.errors[0].param == "password") {
passwordInput.style.borderColor = "red";
} else {
emailInput.style.borderColor = "";
passwordInput.style.borderColor = "";
}
});
}
return data;
})
.catch((error) => console.log(error, "error"));
}
When you send a REST request using fetch() in the browser, the browser doesn't process the response. It's up to your code to look at the status code and body of the response and take any action that you need to. The browser will not change the URL based on the response.
My recommendation is to use 200 to indicate that the login was successful, and then in the browser code, navigate to /auth. In your server code, you should send a 500 status instead when there's an error.
To simulate a redirect, your best bet is to use location.replace (see How do I redirect to another webpage? for a discussion on why):
window.location.replace('/auth.html')
Hi I have managed to store the JWT token generated on Login to a cookie in the browser. How can I use the token to display a list of users from a protected route in Nodejs APi.
I have accessed the token from the cookie using following code
Cookies.get("access")
the Fetch API Code is
const url = "http://localhost:4000/users/";
const getUsers = () => {
fetch(
url,
{ method: "GET" },
{
headers: {
Authorization: "Bearer" + Cookies.get("access"),
"x-auth-token": Cookies.get("access"),
},
}
)
.then((data) => data.json())
.then((prdt) => console.log(prdt));
};
useEffect(getUsers, []);
Node API Code is as follows:
//http://localhost:4000/users
router.get("/", auth, async function (request, response) {
try {
const result = await getAllUsers();
response.send(result);
} catch {
response.status(400).send({
message: error,
});
}
});
the Nodejs Auth Code is as follows:
export const auth = (request, response, next) => {
try {
const token = request.header("x-auth-token");
console.log("token", token);
jwt.verify(token, process.env.SECRET_KEY);
next();
} catch (err) {
response.status(401).send({
error: err.message,
});
}
};
I am not sure where I am going wrong
the Nodejs Part works as tried in Postman The issue is originating on the react side fetch API where I am not sure how to send the keyname "x-auth-token" with jwt token to retrieve the data.
I need to get an authentication cookie from a website, while performing my request using Axios.
var axios = require('axios');
const authentication = async(login, password) => {
var data = `MYPAYLOAD${login}[...]${password}`;
var config = {
method: 'post',
url: 'https://mywebsite.com/login.aspx',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
data : data,
};
try {
return await axios(config, {withCredentials: true});
} catch (error) {
console.log('Error: cannot authenticate...')
}
}
const init = async() => {
const login = 'LOGIN';
const password = 'PASSWORD';
const response = await authentication(login, password);
console.log(response);
}
init()
I'm receiving some Cookies that I need, but the one including the auth token is missing.
If I use exactly the same settings in Postman, I'm receiving the AUTH_TOKEN I'm looking for.
Where am I wrong?
Thanks
I'm trying to build a basic login page with a dashboard using Express server and Nextjs. After the user logs in with proper credentials, they are authenticated and then redirected to the dashboard... Or that's what's supposed to happen at least. It seems that when Router.push("/Dashboard") is called, an improper request is made. However, if I just type http://localhost:3000/Dashboard into the address bar it works.
Get dashboard route
server.get('/Dashboard', checkSignIn, (req, res) => {
console.log("In dashboard")
if(req.session.page_views){
req.session.page_views++;
} else {
req.session.page_views = 1;
}
console.log("Page views: ", req.session.page_views)
return handle(req, res)
})
Log in and redirect from client side
const router = useRouter();
const attemptLogin = async (event: KeyboardEvent) => {
const username: string = event!.target!.username!.value;
const password: string = event!.target!.password!.value;
fetch("http://localhost:3000/SignIn", {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
body: JSON.stringify({ username, password }),
})
.then((res) => {
if (res.status === 200) {
console.log("Status is 200");
return router.push("/Dashboard");
}
})
.catch((err) => console.log("err is", err));
};
Here is what the request looks like when I manually type http://localhost:3000/Dashboard into the address bar
And here is what the request looks like when router.push is called
Hope someone can help with this. Thanks.
Edit: I get these errors (and output) in the console while rediredirecting
So I figured out the issue. It's because I was submitting a form without calling event.preventdefault(), which I think was making an improper fetch request (hence the error above), as well as reloading the page. The new working code for attemptLogin (the function I call on form submit) is
const attemptLogin = async (event: KeyboardEvent) => {
event.preventDefault();
const username: string = event!.target!.username!.value;
const password: string = event!.target!.password!.value;
fetch("http://localhost:5000/SignIn", {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
body: JSON.stringify({ username, password }),
})
.then((res) => {
if (res.status === 200) {
console.log("Status is 200");
return router.push("/Dashboard");
}
})
.catch((err) => {
console.log("err is", err);
event!.target!.reset();
});
};
Architecture: front end Angular, backend nodejs/express.
Currently the setup works as follow:
Login to the site via the Cognito Hosted UI
This redirects to our home page and sends us a code in the URL
I pull down this code in Angular
import { Component, OnInit } from '#angular/core';
import { DbService } from '../db.service';
import { Iss } from '../db.service';
import { Router, ActivatedRoute } from '#angular/router';
import { Http, Response, RequestOptions, Headers} from '#angular/http';
#Component({
selector: 'app-dashboard'
})
export class GroupSelectionComponent implements OnInit {
cognitoCode: string;
constructor(
private DbService: DbService,
private route: ActivatedRoute,
private router: Router
) {}
ngOnInit() {
this.route.queryParams
.subscribe(params => {
console.log(params);
console.log(params.code);
this.cognitoCode = params.code;
});
this.DbService.getIss(this.cognitoCode).subscribe(
iss => this.iss = iss
);
}
In the code you will see I am passing the congitocode to the dbservice for getIss.
db.service
getIss(cognitoCode ): Observable<Issuer[]> {
const url = hosturl +'i_l';
// let header: HttpHeaders = new HttpHeaders();
const httpOptions = {
headers: new HttpHeaders({
'Access-Control-Allow-Origin': '*',
'Content-Type': 'application/json',
'Authorization': cognitoCode
})
};
let params = new HttpParams()
console.log(httpOptions.headers);
return this._http.get(url, httpOptions)
.pipe(
map((res) => {
console.log(res);
return <Issuer[]> res;
})
);
}
I then send the code as part of the headers of my GET request to the backend.
The GET then hits my backend router with these settings.
var authMiddleware = require('../middleware/AuthMiddleware.js');
router.get('/i_l', authMiddleware.Validate, i_l.get);
This will then call my authMiddleware which takes the code provided by Cognito Hosted UI and use a POST against oauth2/token to get my JWT token.
That token is then parsed used to compare to the https://cognito-idp.us-east-2.amazonaws.com/REMOVED/.well-known/jwks.json for congnito.
Once validated the request continues and I get data back from the backend.
// POST that trades the code for a token with cognito
var options = {
'method': 'POST',
'url': 'https://REMOVED.amazoncognito.com/oauth2/token',
'headers': {
'Content-Type': 'application/x-www-form-urlencoded'
},
form: {
'grant_type': 'authorization_code',
'client_id': 'CLIENTIDREMOVED',
'code': req.headers['authorization'],
'redirect_uri': 'http://localhost/group-selection'
}
};
// First request gets the JSON request of the token using the POST above
request(options, function (error, response) {
if (error) throw new Error(error);
token = JSON.parse(response.body).access_token;
//localStorage.setItem('token', token);
// request pull down status based on validitiy of token
request({
url : `https://cognito-idp.us-east-2.amazonaws.com/REMOVED/.well-known/jwks.json`,
json : true
}, function(error, response, body){
console.log('token: ' + token);
if (!error && response.statusCode === 200) {
pems = {};
var keys = body['keys'];
for(var i = 0; i < keys.length; i++) {
var key_id = keys[i].kid;
var modulus = keys[i].n;
var exponent = keys[i].e;
var key_type = keys[i].kty;
var jwk = { kty: key_type, n: modulus, e: exponent};
var pem = jwkToPem(jwk);
pems[key_id] = pem;
}
var decodedJwt = jwt.decode(token, {complete: true});
if (!decodedJwt) {
console.log("Not a valid JWT token");
res.status(401);
return res.send("Not a valid JWT token");
}
var kid = decodedJwt.header.kid;
var pem = pems[kid];
if (!pem) {
console.log('Invalid token - decodedJwt.header.kid');
res.status(401);
return res.send("Invalid token - decodedJwt.header.kid");
}
jwt.verify(token, pem, function(err, payload) {
if(err) {
console.log("Invalid Token - verify");
res.status(401);
return res.send("Invalid token - verify");
} else {
console.log("Valid Token.");
return next();
}
});
} else {
console.log("Error! Unable to download JWKs");
res.status(500);
return res.send("Error! Unable to download JWKs");
}
});
});
Quesiton -- how I set this up so that the Token I get back continues for the user?
If I understand your question properly then you are trying to validate all your apis through cognito user right?
Then you just need to do two things.
Add in header JWT token once you are getting after login. Just store into your application scope and pass everytime whenever any API is calling.
Auth.signIn(data.username, data.password)
.then(user => {
let jwkToken = user.getSignInUserSession().getAccessToken().getJwtToken();
// Store above value in singletone object or application scope.
})
.catch(err => {
//error
});
Now When API is calling pass jwkToken as header.
Then Go AWS ApiGateWay Console and add into Authorizers.