Hi guys,
I made a React + Express + mySQL website. I got it perfectly working on pre-production, however I am now having some problems to get my website correctly run on Render. The error happens when registering the a new user. I want that the user can upload a picture. The picture is stored on the Imgur API and the url is sent to mySQL database. The issue I face is the following:
Access to XMLHttpRequest at 'https://api.imgur.com/3/image' from origin 'https://proyectoescrache.onrender.com' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: 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'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
Register.js:40 Wt {message: 'Network Error', name: 'AxiosError', code: 'ERR_NETWORK', config: {…}, request: XMLHttpRequest, …}
(anonymous) @ Register.js:40
await in (anonymous) (async)
onClick @ Register.js:49
De @ react-dom.production.min.js:54
ze @ react-dom.production.min.js:54
(anonymous) @ react-dom.production.min.js:55
qr @ react-dom.production.min.js:105
Ir @ react-dom.production.min.js:106
(anonymous) @ react-dom.production.min.js:117
cu @ react-dom.production.min.js:274
Pe @ react-dom.production.min.js:52
Yr @ react-dom.production.min.js:109
Gt @ react-dom.production.min.js:74
Wt @ react-dom.production.min.js:73
Show 11 more frames
Show less
Register.js:31
POST https://api.imgur.com/3/image net::ERR_FAILED
(anonymous) @ xhr.js:258
xhr @ xhr.js:49
Un @ dispatchRequest.js:51
_request @ Axios.js:170
request @ Axios.js:40
(anonymous) @ Axios.js:209
(anonymous) @ bind.js:5
(anonymous) @ Register.js:31
onClick @ Register.js:49
De @ react-dom.production.min.js:54
ze @ react-dom.production.min.js:54
(anonymous) @ react-dom.production.min.js:55
qr @ react-dom.production.min.js:105
Ir @ react-dom.production.min.js:106
(anonymous) @ react-dom.production.min.js:117
cu @ react-dom.production.min.js:274
Pe @ react-dom.production.min.js:52
Yr @ react-dom.production.min.js:109
Gt @ react-dom.production.min.js:74
Wt @ react-dom.production.min.js:73
Show 18 more frames
Show less
Register.js:62 Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'data')
at onClick (Register.js:62:37)
This is my code. First, the frontend for registering:
import pe from "../images/login/pe.jpg";
import { useState } from "react"
import axios from "axios"
import { useNavigate } from "react-router-dom"
export default function Register() {
const [inputs, setInputs] = useState({
username:"",
email:"",
password:"",
img: null,
});
const [error, setError] = useState(null);
const navigate = useNavigate();
const handleChange = (e) => {
if (e.target.name === "image") {
setInputs({ ...inputs, img: e.target.files[0] });
} else {
setInputs({ ...inputs, [e.target.name]: e.target.value });
}
};
const uploadImg = async (image) => {
const formData = new FormData();
formData.append("image", image);
try {
const response = await axios.post("https://api.imgur.com/3/image", formData, {
headers: {
Authorization: `Client-ID ${process.env.REACT_APP_IMGUR_CLIENT_ID}`,
Accept: "application/json",
},
});
return response.data.data.link;
} catch (error) {
console.error(error);
throw new Error("Failed to upload image to Imgur.");
}
};
const handleSubmit = async (e) => {
e.preventDefault();
try {
const imgUrl = await uploadImg(inputs.img);
const formData = new FormData();
formData.append("username", inputs.username);
formData.append("email", inputs.email);
formData.append("password", inputs.password);
formData.append("image", imgUrl);
const response = await axios.post("https://proyecto-escrache.onrender.com/api/auth/register", formData);
if (response.data) {
navigate("/login");
}
} catch (error) {
setError(error.response.data);
}
};
return (
<div className="signup-container">
<form className="signupinfo-container">
<img src={pe} alt="log in" />
<input type="text" placeholder="Enter username" required name="username" onChange={handleChange}/>
<input type="email" placeholder="Enter email" required name="email" onChange={handleChange}/>
<input type="password" placeholder="Enter password" required name="password" onChange={handleChange}/>
<input type="file" required name="image" onChange={handleChange}/>
<button onClick={handleSubmit} type="submit">Create a new account</button>
{error && <p>{error}</p>}
</form>
</div>
This is the index.js in my express backend:
const express = require("express");
const cors = require("cors");
require("dotenv/config");
const postRoutes = require("./routes/posts");
const authRoutes = require("./routes/auth");
const cookieParser = require("cookie-parser");
const contactRoutes = require("./routes/contact");
const liveRoutes = require("./routes/live");
const fileUpload = require("express-fileupload")
const app = express();
app.use(cors({
origin: ["https://proyectoescrache.onrender.com", "https://api.imgur.com/3/image", "http://localhost:3000"],
credentials: true,
exposedHeaders: ["Access-Control-Allow-Origin"]
}));
app.use(cookieParser());
app.use(express.json());
app.use(fileUpload())
app.use("/api/auth", authRoutes);
app.use("/api/posts", postRoutes);
app.use("/api/contact", contactRoutes);
app.use("/api/live", liveRoutes);
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => {
console.log("Server is running on port", PORT);
});
And this is the controllers for the registering in the backend:
const db = require("../db");
const bcrypt = require("bcrypt")
const jwt = require("jsonwebtoken")
const nodemailer = require("nodemailer");
const imgur = require('imgur');
const fs = require('fs');
const axios = require("axios")
const register = async (req, res) => {
try {
const { username, email, password, image } = req.body;
const checkQ = "SELECT * FROM users WHERE email=? OR username = ?";
db.query(checkQ, [email, username], (err, data) => {
if (err) return res.status(500).json({ error: err });
if (data.length) return res.status(409).json("User already exists");
const salt = bcrypt.genSaltSync(10);
const hash = bcrypt.hashSync(password, salt);
const insertQ = "INSERT INTO users(`username`, `email`, `password`, `img`) VALUES (?, ?, ?, ?)";
const values = [username, email, hash, image];
db.query(insertQ, values, (err, data) => {
if (err) return res.status(500).json({ error: err });
return res.status(200).json("User has been created successfully");
});
});
} catch (error) {
console.error(error);
return res.status(500).json({ error: 'Failed to upload image to Imgur.' });
}
};
const login = (req, res) => {
const q = "SELECT * FROM users WHERE username = ?";
db.query(q, [req.body.username], (err, data) => {
if (err) return res.status(500).json(err);
if (data.length === 0) {
return res.status(404).json("User not found. Please register first!");
}
const isPasswordCorrect = bcrypt.compareSync(req.body.password, data[0].password);
if (!isPasswordCorrect) return res.status(400).json("Incorrect password. Please, try again!");
const token = jwt.sign({ id: data[0].id }, process.env.JWT_KEY);
const { password, ...other } = data[0];
res.cookie("access_token", token, { httpOnly: true }).status(200).json(other);
});
};
const logout = (req, res) => {
res.clearCookie("access_token", {
sameSite:"none",
secure:true
}).status(200).json("User has been logout")
}
const forgotPassword = (req, res) => {
const q = "SELECT * FROM users WHERE email = ?";
db.query(q, [req.body.email], (err, data) => {
if (err) return res.status(500).json(err);
if (data.length === 0) {
return res.status(404).json("User not found. Please register first!");
}
const resetToken = jwt.sign({ email: req.body.email }, process.env.RESET_TOKEN_SECRET, { expiresIn: "1h" });
const transporter = nodemailer.createTransport({
service: "gmail",
auth: {
user: process.env.EMAIL,
pass: process.env.PASSWORD,
},
});
const mailOptions = {
from: process.env.EMAIL,
to: req.body.email,
subject: "Password Reset Request",
html: `
<p>Hello ${data[0].username},</p>
<p>You requested a password reset. Click the link below to reset your password:</p>
<a href="https://proyectoescrache.onrender.com/reset-password?token=${resetToken}">Reset Password</a>
`,
};
transporter.sendMail(mailOptions, (error, info) => {
if (error) {
console.log(error);
return res.status(500).json("Failed to send reset email.");
}
console.log("Email sent: " + info.response);
return res.status(200).json("Password reset email sent successfully.");
});
});
};
const resetPassword = (req, res) => {
const { token, password } = req.body;
jwt.verify(token, process.env.RESET_TOKEN_SECRET, async (err, decodedToken) => {
if (err) {
return res.status(400).json("Invalid or expired token. Please try again.");
}
const salt = bcrypt.genSaltSync(10);
const hashedPassword = bcrypt.hashSync(password, salt);
const updateQuery = "UPDATE users SET password = ? WHERE email = ?";
db.query(updateQuery, [hashedPassword, decodedToken.email], (updateErr, updateResult) => {
if (updateErr) {
return res.status(500).json({ error: "Failed to send reset email.", details: error.message });
}
return res.status(200).json("Password updated successfully.");
});
});
};
module.exports = { register, login, logout, forgotPassword, resetPassword};
I have been working on these issues for uploading images to Imgur API during the last 3 days and I am desperate for some help. Would appreaciate any help!
Thanks