recently I tried to familiarize myself with React Native.
I found that the POST request for my login method only logged in after the page is refreshed. The POST message also seems like it has been stalled. Unfortunately, this error only occurs on my PC environment, not on my friend's PC.
I'm not sure what is the factor that causes this issues. Would love if anyone had any idea why this only appear on certain PC environment.
Login.js
handleLoginFormSubmit = e => {
e.preventDefault();
const { username, password } = this.state;
axios
.post("/users/login", {
username: username,
password: password
})
.then(res => {
this.setState({
message: "success",
isLoggedIn: true,
});
})
.catch(err => {
this.setState({
username: "",
password: "",
message: `${err.response.data}`
});
});
}
You need async await, because fetching data need uncertain time
Add async on this line
handleLoginFormSubmit = async (e} =>
And await on this line
await axios
Related
const login: SubmitHandler<ILoginValues> = async ({email, password}) => {
try {
const res = await fetch(`${config.apiUrl}/api/login`, {
method: 'POST',
body: JSON.stringify({
email,
password,
}),
});
if (res.ok) {
await setGenericPassword(email, password, CREDENTIALS_STORAGE_OPTIONS);
setUser({isLoggedIn: true, hasSessionExpired: false});
}
} catch (error) {
toast.setToast({message: 'Login failed', visible: true});
}
};
I am creating a login flow in react native using java spring rest api. My Api is running at address http://localhost:8082/api/v1/users how can I get the data from client side using fetch in React native and also store the JWT token in client side.
You can perform the login request when the form is submitted. Than wait for the response and save the jwt in local storage. Than login the user into the logged in ui.
const form = document.getElementById("form-id")
form.addEventListener("submit", async (e) =>{
e.prevetDefault() your code })
I have a sign-up form in my Next.js application.
Undesired behaviour: if the user clicks the "sign up" submit button multiple times in quick succession, then the application makes multiple fetch requests, and multiple toasts are shown on the interface.
Desired behaviour: The user should not be able to perform any actions after pressing submit until the first submit is complete.
My first though was to make the API call synchronous. But for reasons I don't fully understand, this seems to be regarded as a bad idea:
See the only answer here, which advises not to do this: How to make javascript fetch synchronous?
I've looked at other questions along similar lines but the answers did not help:
See How to prevent form from submitting multiple times from client side? Where the top answer doesn't work when there is form validation present. And uses JQuery.
I don't quite understand why a synchronous request is not best practice here. Sure I'm blocking the CPU during an I/O operation, but I don't want the page to be doing anything until the form submission is complete?
What is the recommended method for preventing switch bounce on the form submission and could you explain why?
src/pages/auth/sign-up.js:
const onSubmit = async (data) => {
const { email, password1, password2, first_name, last_name } = data;
const response = await postSignUp( email, password1, password2, first_name, last_name );
// error handling code
toast.success('You have successfully registered!', { autoClose: 2500 })
setTimeout( () => {
router.push({ pathname: '/auth/verify-email', query: { email: email } });
}, 2500 )
/src/lib/api.js:
export async function postSignUp(email, password1, password2, first_name, last_name) {
const response = await fetch(SIGN_UP_ENDPOINT, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify( { email, password1, password2, first_name, last_name } ),
});
const json = await response.json();
return json;
}
A very simple and generally used method is to make the submit button be disabled until you get a response back from your API. So, for example:
Create a state:
const [isSubmitting, setIsSubmitting] = useState(false);
Use that state to set your submit button's disabled attribute:
<button type="submit" disabled={isSubmitting}>Save</button>
Call setIsSubmitting from your event handler:
const onSubmit = async (data) => {
setIsSubmitting(true);
const { email, password1, password2, first_name, last_name } = data;
const response = await postSignUp( email, password1, password2, first_name, last_name );
// error handling code
toast.success('You have successfully registered!', { autoClose: 2500 })
setTimeout( () => {
router.push({ pathname: '/auth/verify-email', query: { email: email } });
}, 2500 )
setIsSubmitting(false);
}
I'm integrating next-auth package to my fresh Next.js project. I have followed all of the Next.js and next-auth documentations but not able to find a solution.
The issue I'm facing goes like this:
I want to Login to my Next.js app using Email & Password submitted to my API Server running on Laravel.
When submitting the login form I'm executing the below function.
import { signIn } from "next-auth/client";
const loginHandler = async (event) => {
event.preventDefault();
const enteredEmail = emailInputRef.current.value;
const enteredPassword = passwordInputRef.current.value;
const result = await signIn("credentials", {
redirect: false,
email: enteredEmail,
password: enteredPassword,
});
console.log("finished signIn call");
console.log(result);
};
And code shown below is in my pages/api/auth/[...nextauth].js
import axios from "axios";
import NextAuth from "next-auth";
import Providers from "next-auth/providers";
export default NextAuth({
session: {
jwt: true,
},
providers: [
Providers.Credentials({
async authorize(credentials) {
axios
.post("MY_LOGIN_API", {
email: credentials.email,
password: credentials.password,
})
.then(function (response) {
console.log(response);
return true;
})
.catch(function (error) {
console.log(error);
throw new Error('I will handle this later!');
});
},
}),
],
});
But when try to login with correct/incorrect credentials, I get the below error in Google Chrome console log.
POST http://localhost:3000/api/auth/callback/credentials? 401 (Unauthorized)
{error: "CredentialsSignin", status: 401, ok: false, url: null}
Am I missing something here?
From the documentation (https://next-auth.js.org/providers/credentials#example)
async authorize(credentials, req) {
// Add logic here to look up the user from the credentials supplied
const user = { id: 1, name: 'J Smith', email: 'jsmith#example.com' }
if (user) {
// Any object returned will be saved in `user` property of the JWT
return user
} else {
// If you return null or false then the credentials will be rejected
return null
// You can also Reject this callback with an Error or with a URL:
// throw new Error('error message') // Redirect to error page
// throw '/path/to/redirect' // Redirect to a URL
}
}
You are not currently returning a user or null from the authorize callback.
Answer posted by shanewwarren is correct, but here is more elaborated answer,
Using axios to solve this
async authorize(credentials, req) {
return axios
.post(`${process.env.NEXT_PUBLIC_STRAPI_API}/auth/login`, {
identifier: credentials.identifier,
password: credentials.password,
})
.then((response) => {
return response.data;
})
.catch((error) => {
console.log(error.response);
throw new Error(error.response.data.message);
}) || null;
},
Hi I am using express for backend authentication and these are my sign in functions/controllers on the front end.
export const signInUser = async credentials => {
console.log('this is for the signInUser', credentials)
try {
const resp = await api.post('/sign-in', credentials)
localStorage.setItem('token', resp.data.token)
return resp.data
} catch (error) {
throw error
}
}
onSignIn = event => {
event.preventDefault()
const { history, setUser } = this.props
signInUser(this.state)
.then(res => setUser(res.user))
.then(() => history.push('/Home'))
.catch(error => {
console.error(error)
this.setState({
loginUsername: '',
loginPassword: '',
})
})
}
setUser = user => this.setState({ user })
and this is my sign in controller on the backend
const signIn = async (req, res) => {
try {
console.log('hello' ,req.body);
const { loginUsername, username, loginPassword } = req.body;
const user = await User.findOne({
where: {
username: loginUsername
}
});
console.log('this is the user', user)
if (await bcrypt.compare(loginPassword, user.dataValues.password_digest)) {
const payload = {
id: user.id,
username: user.username,
password: user.password
};
const token = jwt.sign(payload, TOKEN_KEY);
return res.status(201).json({ user, token });
} else {
res.status(401).send("Username or Password is invalid- try again.");
}
} catch (error) {
return res.status(500).json({ error: error.message });
}
};
The issue is the state of the user doesn't persist on refresh but I still have the json webtoken in my local storage and this is an issue when I make post requests and even signing up since I am redirecting to the home page and losing the user state. Any help would be appreciated!
From your tags, I noticed that you are using React, so the solution is simple!
you can have an GlobalAuthManager context for your application that would wrap all the components at the most higher level! after <React.strictMode> like below:
<React.StrictMode>
<GlobalAuthManager.Provider value={{authData}}>
<App />
</GlobalAuthManager.Provider>
</React.StrictMode>
As you might guess, this would be a context! that would provide you your user data to all your components!
The Pattern:
1. Store token:
when your user logins to your app, you would receive a token ( in your response or in response header ), you need to store the token value in localstorage, or more better in cookie storage (there are a lot of articles about it why), one is here.
2. have a /getUserData endpoint in backend:
you need to have a /getUserData endpoint in backend to retrive your user data based on token
3. call /getUserData in app mount:
before every thing in your app, you need to call this endpoint if you find token in localstorage or cookie storage. so if you run this in your componnetDidMount or useEffect(() => { ... }, []), that would work!
4. store your user data and state in context:
after you've called the /getUserData and if you had a valid token(i mean not expired token or not interrupted and edited token) , you will get you user data and what you need to do is that you need to store this in your GlobalAuthManager and provide that in to your Global App component!
after that you have your user data available to you that you can decide to show login or sign up button in your Navbar or disable/enable comment section for example based on your user data!
Wrap up:
So the key is that you have to have a GlobalAuthManager for only one purpose, that before every thing it runs in the top level in your app and gets you your user data based on provided token from localstorage or cookie storage!
after that you can manage your app state based on that your user is logged in or not!
I'm using nuxt to develop a client for my laravel project.
In the login.vue component I have the following JS code
import Form from 'vform'
export default {
head () {
return { title: this.$t('login') }
},
data: () => ({
form: new Form({
email: '',
password: ''
}),
remember: false
}),
methods: {
async login () {
let data;
// Submit the form.
try {
const response = await this.form.post('/api/login');
data = response.data;
} catch (e) {
return;
}
// Save the token.
this.$store.dispatch('auth/saveToken', {
token: data.token,
remember: this.remember
});
// Fetch the user.
await this.$store.dispatch('auth/fetchUser');
// Redirect home.
this.$router.push({ name: 'home' })
}
}
}
If I try to submit the login form with wrong email and password values I see an error message in a browser console.
For example:
POST http://laravel.local/api/login 422 (Unprocessable Entity)
Please note that I'm using try catch that catches all errors on the following call.
const response = await this.form.post('/api/login');
Is this really issue with async/await usage?
How can I get rid of that error in the browser console?
If you need some more info from me do not hesitate to ask it.