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" });
}
})
Related
two questions regarding a NextJS/Typescript website I'm making! Currently, I have an authentication function from the front-end, that is then handled on my backend server. As you can see in the code below, this function returns a res.status(400) when there is an error and a res.status(200) when everything works correctly. However, I can't seem to store this status in the responseVariable that awaits for the function to end. Instead, it immediately displays an error on my front-end console. This, however, isn't true when the status is 200; in which case I can actually print out the returned status. So my two questions are:
Why can't I access the responseVariable when it is a status 400 response?
I understand I can catch the error instead of looking at the responseVariable, but I can't seem to access the "Missing username" message that should be within the error. Logging error.message returns "Request failed with status code 400"; any way to access the custom message within the JSON? Edit: When I try logging error.response.message, I get the error: "Property 'response' does not exist on type 'Error'."
Authentication function called on front-end:
const handleAuthentication = async () => {
try {
const responseVariable = await axios({
method: 'POST',
url: '/api/auth',
data: {
username: account,
},
})
console.log(responseVariable) //I get here for 200 status, but not 400
} catch (error) {
console.log(error.message)
}
}
Back-end auth handler:
import type { NextApiRequest, NextApiResponse } from 'next'
import { sign } from 'jsonwebtoken'
const Auth = async (req: NextApiRequest, res: NextApiResponse) => {
const { username } = req.body
if (!username) {
res.status(400).json({ message: 'Missing username' })
return
}
const token = sign({ username },process.env.TOKEN_SECRET as string)
return res.status(200).json({ token })
}
}
export default Auth
You must use this form for get access to the message that return from api
error.response.data.message
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);
});
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.
When I tried to check the condition for the response status, it is not even going inside and checking if, what should be done to compare and show the alert. FYI swal is a npm package used for alert
onSubmit(values) {
this.props.signIn(values, response => {
if (response.status === 200) {
swal("Login successful", "Signed In", "success");
this.props.history.push(`/dashboard/${response.data.user_name}`);
} else {
console.log("wrong password");
swal({
title: "Invalid Email Id or password",
icon: "warning"
});
}
});
};
Action.js
export function signIn(values, callback) {
const request = axios.post(`${ROOT_URL}/${APP_ID}/${API_KEY}/users/login`, values).then(() => callback());
return {
type: LOGIN_DETAILS,
payload: request
};
}
Need to return axios promise, try with that code
onSubmit(values) {
this.props
.signIn(values)
.then((response) => {
swal("Login successful", "Signed In", "success");
this.props.history.push(`/dashboard/${response.data.user_name}`);
})
.catch((error) => {
console.log("ajax error");
swal({
title: "Invalid Email Id or password",
icon: "warning",
});
});
}
first error is response.status will be undefined because you didn't pass response back in callback()
second one is if axios.post fail it will never call callback(), that mean the whole if else won't work.
To fix this you just need to change your action to this
export function signIn(values, callback) {
const request = axios.post(`${ROOT_URL}/${APP_ID}/${API_KEY}/users/login`, values).then(callback).catch(callback);
return {
type: LOGIN_DETAILS,
payload: request
};
}
or
export function signIn(values, callback) {
const request = axios.post(`${ROOT_URL}/${APP_ID}/${API_KEY}/users/login`, values).then((response) => callback(response)).catch((error) => callback(error));
return {
type: LOGIN_DETAILS,
payload: request
};
}
So, along with Redux-Form I am using axios and thunk as middleware, and when I am in the onSubmit function (loginUser), and do AJAX calls with Axios. Unfortunately, when I want to signal that my user's submitted credentials are invalid and throw a SubmissionError to signal that the onSubmit function failed, and therefore get the errors displayed on the form I am getting "Uncaught (in promise)".
I have read from other threads that I might have to return a promise at some point, but I'm not entirely sure how to implement that (if that is even the problem).
Currently using version Redux-Form 6.5.0. Any help would be appreciated.
import axios from 'axios';
import { SubmissionError } from 'redux-form';
export function loginUser({ email, password }) {
return function(dispatch) {
axios.post(`${API_URL}/authenticate`, { email, password })
.then(response => {
console.log('status is: ', status, ' response is: ', response);
if(response.data.token){
cookie.save('token', response.data.token, { path: '/' });
dispatch({ type: AUTH_USER });
browserHistory.push('/');
} else {
if(response.data.success === false) {
var errObj = { email: "Invalid email and password combo", _error: "That email and password combination did not work. Please try again."};
throw (errObj)
}
}
})
.catch((error) => {
throw(new SubmissionError(error));
})
}
}
Error in console:
Uncaught (in promise) >
SubmissionError
errors
:
Object
message
:
"Submit Validation Failed"
name
:
"SubmissionError"
stack
:
"SubmissionError: Submit Validation Failed↵ at eval (eval at <anonymous> (http://localhost:8080/bundle.js:14:22671), <anonymous>:94:1297)"
__proto__
:
ExtendableError
For those of you wondering, I used 'resolve' and 'reject' with the SubmissionError inside of the reject() function as such (also notice the new Promise part at the top):
export function registerUser({ email, password }) {
return new Promise((resolve, reject) => {
axios.post('http://localhost:8088/api/users', { email: email, password: password })
.then(response => {
console.log('response is: ' , response, 'response.data is: ', response.data, 'response.code is: ', response.code);
if(response.data.success){
console.log('registerUser response.data.success is true')
cookie.save('token', response.data.token, { path: '/' });
store.dispatch({ type: AUTH_USER });
browserHistory.push('/');
resolve();
} else {
if(response.data.code === 11000){ //duplicate email
console.log('data code = 11000')
var errObj = new SubmissionError({_error: 'User registration failed, email already exists.' }) //need to add store dispatch for failed user registration (for form feedback)
reject(errObj);
} else if (response.code === 2) {
console.log('response.code = 2')
var errObj = new SubmissionError({ email: 'Invalid email pattern.' })
reject(errObj);
}
}
}).catch((error) => {
console.log('error is: ', error)
//errorHandler(store.dispatch, error, AUTH_ERROR)
if(error instanceof SubmissionError) reject(error);
});
})
}