React Cors issue with ExpressJS - reactjs

EDIT: I am getting the following error when trying to access my server:
POST http://localhost:3001/user/login 500 (Internal Server Error)
I'm not sure where I'm going wrong for this error to keep occurring:
React:
export default class Account extends React.Component {
constructor() {
super();
this.state = {
isLoggedIn: false,
};
this.login = this.login.bind(this);
}
componentDidMount() {
const cookies = new Cookies();
const user = cookies.get('user');
const pass = cookies.get('pass');
this.setState({processing: true})
fetch('http://localhost:3001/user/login', {
credentials : 'omit',
method : 'POST',
body : JSON.stringify({
username : user,
password : pass
})
})
.then(res => res.json())
.then(json => {
// If the login was successful
if (json.success) {
this.setState ({
isLoggedIn: true
})
}
// Otherwise
else {
this.setState({
errorMessage: 'Invalid username or password',
processing : false
});
}
})
.catch(() => {
this.setState({
errorMessage: 'An unknown error occurred',
processing : false
});
});
}
render() {
if(this.state.isLoggedIn) {
return (<p> Logged In</p>);
}
else {
return (<p> Not Logged In</p>);
}
}}
Express:
router.post('/login', (req, res) => {
return User
.findOne({username: req.body.username})
.then (user => user.authenticate(req.body.password))
.then (auth => {
if (auth.user !== false) {
req.session.user = auth.user.user
}
res.json({success: auth.user !== false})
})
.catch(() => res
.status(500)
.json({success: false})
);
});
This error isn't giving much info on what I could be doing wrong but it could be to do with cors.

There problem is not in your code ( probably ); since a request will be considered as SAME-ORIGIN if domain, port and protocol all be the same in source and destination of the request; but your request is heading to port 3001 not 3000 which violates the same-origin rule; hence CROSS-ORIGIN; two other part are ok, both on localhost and http but port different; you need to configure your server to respond properly to OPTION(pre flight) request to fix this properly;

Have you added a proxy parameter to the package.json? I use this setup frequently but have not seen the issue you are seeing. Try adding the following parameter to the package.json
{
"name": "mern",
"version": "0.1.0",
"proxy": "http://localhost:3001/"
...
}
And then all of your API calls can just be /api because the proxy parameter has been set.

Your console reads: Cannot read property 'authenticate' of null.
In your .catch of api -
.catch(() => res
.status(500) // you are sending 500 (internal server error) irrespective of what your actual error is//
.json({success: false})
);
Your error is -
return User
.findOne({username: req.body.username})
.then (user => user.authenticate(req.body.password)) //can read authenticate of null because user is null i.e This user does not exist in your DB. //
I suggest add err in your catch block as parameter and do proper error handling. This issue is the case of improper error handling.

Related

500 internal server error in restful api when I send a value as true and works if I send it as false

I am try to call an API but when I send isRestart : true, I get 500 internal server error and when I send the same data with **isRestart: false **, I get a response and status 200, so its working fine on false statement but its giving me 500 error on true statement. any ideas what might be causing it ?
const resetExam = () => {
const resetExamData = {
studentId: student_id,
studentType: student_type,
isRestart: true,
};
axios
.post(`https://myapiurl.net/api/getExamList`, resetExamData)
.then((response) => {
console.log(response.data.data);
})
.catch((error) => {
console.log(error, "Error Loading Reset APi, Please Try Again !");
});
};
Note : message : "Creating default object from empty value" // This is what it says in the developer console network tab.

How to handle login failed error in NextAuth.js?

I'm using NextAuth.js for Next.js authentication. Login works fine, but the page is still reloading on wrong credentials. It doesn't show any error. I need to handle error to show some kind of toast message.
signIn("credentials", {
...values,
redirect: false,
})
.then(async () => {
await router.push("/dashboard");
})
.catch((e) => {
toast("Credentials do not match!", { type: "error" });
});
When passing redirect: false to its options, signIn will return a Promise that always resolves to an object with the following format.
{
error: string | undefined // Error code based on the type of error
status: number // HTTP status code
ok: boolean // `true` if the signin was successful
url: string | null // `null` if there was an error, otherwise URL to redirected to
}
You have to handle any errors inside the then block, as it won't throw an error.
signIn("credentials", { ...values, redirect: false })
.then(({ ok, error }) => {
if (ok) {
router.push("/dashboard");
} else {
console.log(error)
toast("Credentials do not match!", { type: "error" });
}
})

Image with public URL from GCS won't display immediately after state update but works after refreshing the page

I have a form that uploads data into mongoDB and an image into a bucket in Google Cloud Storage using #google-cloud/storage. These images have public URLs. After submission, I immediately make an API call into my backend and then update my states. However, the image that was recently uploaded won't display and only responds with a 403 error. error on get request on the public URL using img tag
My Submit handler function:
const handleSubmit = async () => {
const repairData = new FormData();
try {
if (state.device && state.issue && state.image) {
repairData.append("device", state.device);
repairData.append("customer", user._id);
repairData.append("issue", state.issue);
repairData.append("image", state.image);
repairData.append("expedite", state.expedite);
await api.post("/requests/create", repairData, {
headers: { "auth-token": token },
});
setState({
device: "",
issue: "",
image: null,
expedite: "No",
hasError: false,
errorMessage: "",
});
setShow(false);
getRepairs();
} else {
setState({
...state,
success: false,
hasError: true,
errorMessage: "Missing required information!",
});
}
} catch (error) {
console.log(error);
}
};
My API Call Function:
const getRepairs = async () => {
try {
const response = await api.get("/user/requests/", {
headers: { "auth-token": token },
});
setRequests([...response.data.repairs]);
} catch (error) {
console.log(error);
}
};
Only the cached images were displayed. When the page is refreshed, the image will then be displayed accordingly. I can also view the images on browser. I have tried may things such as this one but it still does not work.
As #Jan Hernandez said, I checked my google cloud upload function and it was responding even though it's not finished uploading yet! Silly me.
Original
await storage
.bucket(process.env.BUCKET_NAME)
.upload(filename, options, (err, file, cb) => {
if (err)
return res.status(409).json({
message: "Error uploading!",
});
});
return res.status(200).json({
repair: req.repair,
message: "Upload successful",
});
Correct
await storage
.bucket(process.env.BUCKET_NAME)
.upload(filename, options, (err, file, cb) => {
if (err)
return res.status(409).json({
message: "Error uploading!",
});
res.sendStatus(200);
});

React object fetched from API is missing properties

I am fetching a profile object from my API following user authentication. The fetch returns the profile object as expected, however my server logger clearly shows a profile object containing an "id" and "username", but the initial object returned to the client has only the "username". I am only able to access the "id" property of the profile abject after I refresh.
Not sure how to fix this, but ive tried everything I can think of...
Login Form
export default class LoginForm extends Component {
static defaultProps = {
onLoginSuccess: () => { }
}
state = { error: null }
handleSubmitJwtAuth = ev => {
ev.preventDefault()
this.setState({ error: null })
const { username, password } = ev.target
//login request
AuthApiService.postLogin({
username: username.value,
password: password.value,
})
//login response
.then(res => {
//updates context profile with username value after login
this.props.updater({ username: username.value })
username.value = ''
password.value = ''
TokenService.saveAuthToken(res.authToken)
this.props.onLoginSuccess()
})
.catch(res => {
this.setState({ error: res.error })
})
}
Profile API Service
const ProfileApiService = {
getProfile() {
return fetch(`${config.API_ENDPOINT}/profile`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': `bearer ${TokenService.getAuthToken()}`
}
})
.then(res => {
return (!res.ok)
? res.json().then(e => Promise.reject(e))
: res.json()
}
);
}
}
(API) Profile Service
const ProfileService = {
getProfile : (db,id) =>{
return db
.from('v_users')
.select('id','username')
.where({id})
.first();
},
serializeProfile(profile){
return {
id: profile.id,
username: xss(profile.username)
};
}
}
initially, console.log(this.state.profile.id) //undefined
after a refresh, console.log(this.state.profile.id) // 7
the server log shows this object being returned initially
{ id: 7, username: 'qber83' }, however as mentioned above, I am unable to access the "id" property without refreshing the browser.
The problem here could be that your state is not updated properly, since the object returned is right the API services work, so here your context updater or this.props.onLoginSuccess() might contain the issue.

React Microsoft Outlook Calendar data Without Login Session using Hello.js

I am creating a React calendar that take data from "Microsoft Outlook Calendar" using the client-side JavaScript SDK "hello.js" and Microsoft Graph (for the set up I also followed this guide: https://learn.microsoft.com/en-us/graph/auth-register-app-v2).
Using hello.login my app shows the calendar without any problem...but unfortunately I have to show it without a login session.
This is my code:
class CalendarView extends Component {
constructor(props) {
super(props);
hello.init({
microsoft: {
id: APP_ID,
oauth: {
version: 2,
auth: 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize',
},
scope_delim: ' ',
form: false,
scope: SCOPES,
},
});
const { startDate, endDate } = this.props;
this.state = {
// events: [],
startDataTime: startDate.toISOString(),
endDataTime: endDate.toISOString(),
token: hello('microsoft').getAuthResponse().access_token,
};
}
In this other component I mange the Microsoft Graph Query:
class EventsList extends Component {
constructor() {
super();
this.state = {
events: [],
};
}
componentWillReceiveProps(nextProps) {
const { startDate, endDate, token } = nextProps;
// to know what is the Bearer toke
// -> https://stackoverflow.com/questions/25838183/what-is-the-oauth-2-0-bearer-token-exactly
axios.get(
`https://graph.microsoft.com/v1.0/me/calendarview?startdatetime=${startDate}&enddatetime=${endDate}&orderby=start/dateTime`,
{ headers: { Authorization: `Bearer ${token}` } },
).then(response => this.setState({ events: response.data.value }))
.catch((error) => {
console.log(error.response);
});
}
render() {
const { events } = this.state;
if (events !== null) return events.map(event => <EventList key={event.id} event={event} />);
return null;
}
}
The strange thing is that if I make a console.log(token) the app show me the token but, at the same time, I receive an "GET...401 (Unauthorized)" error
console log token and error message
That are my app propriety:
app propriety part 1
app propriety part 2
Maybe the problem is the Hello.js call?
I am testing my app with Jest and I have this error, can it be linked to my problem?
console.error node_modules/jest-environment-jsdom/node_modules/jsdom/lib/jsdom/virtual-console.js:29
Error: Uncaught [TypeError: hello is not a function]
How Can I solve?
I found the solution!
I had to make 2 axios call:
one to obtain the token (with a POST)
one for use the token in my microsoft graph query (with a GET)
I had to register my app here https://portal.azure.com/#home so to obtain a Client ID and Secret.
After I needed to send a POST message to Azure Active Directory Authentication endpoint with following body parameters:
grant_type: The flow we want to use, client_credentials in my case.
client_id: The Client ID (Application ID) of the application I
created in the registration step;
client_secret: The Client Secret I created in the registration
step;
resource: The name of the resource I would like to get access,
https://graph.microsoft.com in this case.
So I created one component with the following axios POST request:
componentDidMount() {
axios.post(`https://cors-anywhere.herokuapp.com/https://login.microsoftonline.com/${AZURE_ACTIVE_DIRECTORY_TENANT_NAME}/oauth2/token`,
`grant_type=${GRANT_TYPE}&client_id=${APP_ID}&client_secret=${SECRET}&resource=${RESOURCE}`).then(res => this.setAccessToken(res.data.access_token))
.catch((error) => {
console.error(error.response);
});
}
setAccessToken(token) {
if (typeof token === 'string') this.setState({ accessToken: token });
}
NOTE
the resource value needed to be a bit changed to work:
https%3A%2F%2Fgraph.microsoft.com%2F
I had to put the string 'https://cors-anywhere.herokuapp.com' before micorsoftonline URL because otherwise the application generated
"a blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource."
(I don't know why, I am still working on it because putting this string before is not an optimal solution).
In EventList component I didn't need hellojs anymore, so I just use the token I generated to access. I had to change just a bit the microsoft graph query:
componentDidMount() {
const { accessToken } = this.props;
const { startDate, endDate } = this.state;
this.getEvents(startDate, endDate, accessToken);
}
getEvents(startDate, endDate, accessToken) {
const startDateString = startDate.toISOString();
const endDateString = endDate.toISOString();
axios.get(
`https://graph.microsoft.com/v1.0/users/${USER_PUBLIC_ID}/calendarview?startdatetime=${startDateString}&enddatetime=${endDateString}&orderby=start/dateTime`,
{
headers: {
Authorization: `Bearer ${accessToken}`,
},
},
).then(response => this.setEvents(response.data.value))
.catch((error) => {
console.error(error.response);
});
}
setEvents(events) {
const validEvent = event => typeof event.subject === 'string';
this.setState({ events: events.filter(validEvent) });
}
I hope that my solution can be usefull also to other users

Resources