404 Error when making a POST request using fetch() - mysql

I am following this tutorial from Hakernoon to set up Node.js with MySQL using my machine as local server.
I am using a few different tools, but they don't seem to be a problem. I'm using:
Ubuntu 16.04
Node.js
MySQL Workbench (He uses Homebrew because his is a Mac)
MySQL
knex.js
Express
*(Ubuntu and Workbench are the only differences)
Summarizing,the whole tutorial works well except when I reach the part of 'Login'. Here, we build a form to enter the user name and password making a POST requests. Then, if everything is OK, it returns a 200 status, else shows a message saying the login failed. And here is the problems. Every time I try to log in (even when being sure the credentials are correct and knowing that that user is stored in the database) it tells me that the login fails.
Checking on the browser inspect tool, it shows a Fail to load resources: the server responded with a status of 404 (Not found). It also points out that the problems is in the fetch() function I use in my post function to make the POST requests.
I checked the documentation on fetch() but is does not clarify much. Also I tried to contact the author of the tutorial and I got no answer. What am I doing wrong with fetch to give me the 404 status?
Also, every time I create a new user (also a POST request), it does it with no problem and I can see it in the database in MySQLWorkbench.
This is the file (app.js) with the code to create users and login:
const CreateUser = document.querySelector('.CreateUser')
CreateUser.addEventListener('submit', (e) => {
e.preventDefault()
const username = CreateUser.querySelector('.username').value
const password = CreateUser.querySelector('.password').value
post('/createUser', { username, password })
})
const Login = document.querySelector('.Login')
Login.addEventListener('submit', (e) => {
e.preventDefault();
const username = Login.querySelector('.username').value
const password = Login.querySelector('.password').value
post('/login', {username, password})
.then(({status}) => {
if(status === 200)
alert('login success')
else
alert('login failed')
})
})
function post (path, data) {
return window.fetch(path, { <========= Here is where the browser shows the problem
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
})
}
***I am not posting the rest of the code to not make it too long, if more info is needed, let me know). Thanks!

Related

CredentialsError: Could not load credentials from ChainableTemporaryCredentials in AWS-SDK v2 for Javascript

I am trying to set up temporary credentials in the AWS-SDK v2 for Javascript:
const aws = require('aws-sdk')
aws.config = new aws.Config({
credentials: new aws.ChainableTemporaryCredentials({
params: {
RoleArn: roleArn, // Defined earlier
RoleSessionName: sessionName, // Defined earlier
DurationSeconds: 15 * 60
},
masterCredentials: new aws.Credentials({
accessKeyId: accessKeyId, // Defined earlier
secretAccessKey: awsSecretAccessKey // Defined earlier
})
}),
region: 'us-east-1',
signatureVersion: 'v4'
})
aws.config.getCredentials(function (err) {
if (err) console.log(err.stack)
else console.log('Access key:', aws.config.credentials.accessKeyId)
})
However, I'm keep getting the following error, which occurs when calling getCredentials:
CredentialsError: Could not load credentials from ChainableTemporaryCredentials
Note that it works fine if I set the credentials parameter to the master credentials instead of the temporary credentials, as shown below:
aws.config = new aws.Config({
credentials: new aws.Credentials({
accessKeyId: accessKeyId, // Defined earlier
secretAccessKey: awsSecretAccessKey // Defined earlier
}),
region: 'us-east-1',
signatureVersion: 'v4'
})
Does anyone know what's causing this issue? Here's the documentation I was referencing:
https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Config.html
https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Credentials.html
https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/ChainableTemporaryCredentials.html
I was finally able to figure out the cause of this error.
What led me to figure out the cause of the error was when I printed out the full error instead of just the most recent error. One of the properties of the error was:
originalError: {
message: 'The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.',
code: 'SignatureDoesNotMatch',
time: 2021-12-11T19:49:52.395Z,
requestId: '402e4c32-7989-4287-a6a9-628bfc93f60f',
statusCode: 403,
retryable: false,
retryDelay: 39.60145242362791
}
So I realized the problem was that my masters credentials I provided were not correct!
I have actually always known that these credentials weren't correct, but for unit-testing purposes it seemed to work fine with these incorrect credentials as long as I didn't also supply the temporary credentials. But now I understand that the getCredentials function verifies the credentials with AWS if you're using temporary credentials, but doesn't verify with AWS when using just master credentials. That explains that strange behavior I was seeing.

Node Lambda: MySQL query never runs

Testing with Postman, I'll try to make this as clear as possible, please advise if this is not making sense.
I have a Lambda that uses MySQL RDS database on AWS and works fine locally when accessing the database on AWS. After successfully getting a JWT from an auth endpoint I try to hit the login endpoint and I get a 502 Bad Gateway. Using the CloudWatch logs I can trace the failure to right before the login query runs. I've confirmed that my MySQL config is correct and that I have a connection to the database. The lambda and the database are in the same region DB: us-east-1f, lambda: us-east-1.
I've confirmed the OPTIONS and POST request methods for this endpoint both are set up with CORS enabled in the API Gateway. I'm using my serverless.yml to set cors: true on all the endpoints even though I'm using app.use(cors()) in my index file.
The error message for the 502 is, {"message": "Internal server error"}
Here is the point of failure in my code:
'use strict';
const mysql = require('./index');
module.exports = {
loginSql: async (email, password) => {
// MAKES IT HERE AND THE PARAMS ARE CORRECT
try {
console.log('IN TRY %%%%%%%%%%%%%%');
// SEEMS TO DIE HERE
const results = await mysql.query({
sql: `SELECT
id, first_name, last_name, email
FROM users
WHERE email = ?
AND password = ?`,
timeout: 50000,
values: [email, password],
});
// NEVER MAKES IT HERE /////////
console.log('QUERY RAN %%%%%%%%%%%%');
mysql.end();
if (results.length < 1) return false;
return results;
} catch (error) {
// DOESN'T THROW ERROR
console.log('LOGIN DB ERROR', error);
throw new Error('LOGIN DB ERROR THROWN', error);
}
},
};
I just created the exact same use case in that I have a LAMBDA function written in Java querying data from a MySQL RDS instance. It works perfectly.
Here is your issue:
To connect to the RDS instance from a Lambda function, you must set the inbound rules using the same security group as the RDS Instance. For details, How do I configure a Lambda function to connect to an RDS instance?.

/favicon.ico after login in Node JS

I have created a login/register system using express (passport) on my website and I am saving the originalUrl before the user was redirected to the login page but every time after the login, the user is redirected to /favicon.ico instead of the saved Url. Could someone tell me what is the cause of the issue?
My app.use():
app.use((req, res, next) => {
if (!['/login'].includes(req.originalUrl)) {
req.session.returnTo = req.originalUrl;
}
res.locals.currentUser = req.user;
res.locals.success = req.flash('success');
res.locals.error = req.flash('error');
next();
})
My /login get and post request:
app.get('/login', (req, res) => {
res.render('login');
})
app.post('/login', passport.authenticate('local', { failureFlash: true, failureRedirect: '/login' }), (req, res) => {
const redirectUrl = req.session.returnTo || '/';
console.log(redirectUrl);
delete req.session.returnTo;
res.redirect(redirectUrl);
})
You have a race condition in your session between two incoming requests.
Your app.use() middleware is going to see the /favicon.ico request and will overwrite the req.session.returnTo value that your login route may have just set. If these two requests come in one immediately after the other (which is likely when a browser first visits your site), then the /favicon.ico route will mess up the session state you just tried to set with the /login route.
I can't tell what that middleware is trying to do, but it looks like it's very capable of overwriting stuff in the session that other requests are in the middle of using. Redirects after login are much, much safer to do by putting the eventual redirect URL in the query parameter. Then it is stateless on the server and isn't subject to these types of race conditions when there is more than one incoming request to the server form the same user.
FYI, you could also fairly easily prevent this particular problem (though not other potential race conditions) by just putting this route handler before your middleware:
// put this before your middleware
app.get("/favicon.ico", (req, res) => {
res.sendStatus(404);
// or instead of a 404, send an actual favicon.ico file
// just don't let routing continue to your middleware
});
This would keep your middleware from running at all when /favicon.ico is requested and thus prevent that specific place that a race condition with your session data is caused.

Is sending login credentials to server for authentication and authorization in body with content-type: application/json acceptable?

I was looking through multiple stack overflow questions and answers but wasn't able to get anything definitive when it comes to making a request to a server for login authentication and authorization.
My question: Is sending login credentials to server for authentication and authorization in body with content-type: application/json acceptable?
const handleSubmit = (e) => {
e.preventDefault();
const formData = new FormData(e.target);
const [email, password] = formData.values();
fetch('/login', {
method: 'POST',
headers : {'Content-Type' : 'application/json'},
body: JSON.stringify({email, password})
}).then(result =>{ //result is a ReadableStream object
return result.json(); //result.json() parses the data into useable format (json)
}).then(data => {
if(data.isAuthenticated){
handleUserAuthChange(true, ()=>{
history.push('/vehicles');
});
}
}).catch(err => console.log(err));
}
As long as you are using HTTPS, yes. This is a pretty common way of handling login requests
There is a great "tutorial" here on stackoverflow.
Unless the connection is already secure (that is, tunneled through HTTPS using SSL/TLS), your login form values will be sent in cleartext, which allows anyone eavesdropping on the line between browser and web server will be able to read logins as they pass through. This type of wiretapping is done routinely by governments, but in general, we won't address 'owned' wires other than to say this: Just use HTTPS.
In short, you want to always use HTTPS to be sure it's safe.

How can I fix this CORS with Socket.io?

I'm having trouble migrating my locally hosted chat application using Socket.io to my live cloud server. I am aware there are solutions out there, however, I cannot find anything that solves my problem.
I am receiving "Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at.... (Reason: CORS request did not succeed)"
'''
const io = require('socket.io')(3000)
io.on('connection', socket => {
socket.on('new-user', name => {
users[socket.id] = name
socket.broadcast.emit('user-connected', name)
})
socket.on('send-chat-message', message => {
socket.broadcast.emit('chat-message', {message: message, name:
users[socket.id]})
})
socket.on('disconnect', () => {
socket.broadcast.emit('user-disconnected', users[socket.id])
delete users[socket.id]
})
})
Above is the server.js file.
const socket = io('<url>:3000')
const messageForm = document.getElementById('send-container')
const messageInput = document.getElementById('message-input')
const messageContainer = document.getElementById('message-container')
This is the script my app is using, the is replaced by mine, it just masked on here.
Things I have tried:
Setting headers using "Header set Access-Control-Allow-Origin" in my Apache & Nginx config
Changing the url on the script
Changing the ports
So far I've no luck, please help me!!
Try
// Allow all origins
io.origins('*');
source