Redirection after successful login operation - reactjs

I am facing a problem while I am trying to redirecting user to home page after successful login. I am using this example in github.
https://github.com/cornflourblue/react-redux-registration-login-example
In this file, "src/LoginPage/LoginPage.jsx", There is such a part which sends login request in a POST message but I do not see any redirection to home page, just login page. Here is the part:
handleSubmit(e) {
e.preventDefault();
this.setState({ submitted: true });
const { username, password } = this.state;
const { dispatch } = this.props;
if (username && password) {
dispatch(userActions.login(username, password));
}
}
When I look at the network activity, I see that I receive successful message from response of server. Do I need to add something that does redirection?

Yes you need to add Browser Routing to your project and after a successful login you should redirect to page which you want. For example to="/Home". At first you need something like isAuth in your redux reducer. After login submit, if it is successful set this to true and in your LoginPage with mapStateToProps get this isAuth value. Also in your render() section use this before your other jsx code ->
render() {
let redirect = null;
if(isAuth == true){
redirect = <Redirect to="/Home" />;
}
return (
{redirect}
)
}

I found the reason of problem. If response is successful, something has to be set into localStorage. In private route, it checks whether that thing exists in localStorage. If not, it does not do anything but if it has, it operates the component to be redirected. I forgot to edit this part. That's why, it did not do redirection.

Related

Directly redirect to AAD login page on hitting the URL in browser

Using MSAL 2.0 in React we can easily achieve redirect to login page using below methods
Login with pop-up
Login with redirect
But both the methods can be performed on a login/signin button action.
In my case, I want to redirect my React app directly to login page, when the URL is hit in the browser i.e. without button action.
Also, while doing the redirect I also need to pass my multiple scopes, for user consent.
I did some research but didn't found any feasible solutions.
Please can anyone help me with this ?
When an application starts it always start with the app.js. In the app.js class constructor you can check your token if it is valid/invalid and or if expired.
In order to redirect your React app directly to login page try this:
state = {
show: false;
}
componentWillReceiveProps(nextProps) {
if (nextProps.children !== this.props.children) {
this.checkAuth();
}
}
componentDidMount() {
this.checkAuth();
}
checkAuth() {
Api.checkAuth()
.then(result => {
if (result.success) {
this.setState({ show: true });
} else {
return <Redirect to='/login' />
}
});
}

How to redirect an user to a specific webpage after Google Sign In with Redirect in Firebase?

The nature of the sign-in flow with Google/Facebook is that after we login in the redirected page of Google, it comes back to our website's sign-in page.
The following code runs when the Google/Facebook login button is clicked:
fire.auth().signInWithRedirect(provider);
So, my current approach is that I check the Firebase user object using the onAuthStateChanged() function. If the user state is populated, I render a component, else if it is null, I render the component.
{user ? (
<Home />
) : (
<Signup />
)}
But the problem is that after logging in using Google or Facebook, the component is showing for some time (maybe 1-2 secs) and then rendering the component.
I want to render the component immediately after I login using Google redirect. What should I do?
google and facebook login system are asynchronous in nature so you shoud you async await method inside you code.
You should show a full loading state in the login screen when clicking on the signin button
So when the authentication starts show the user a loader,
and if fails stop the loader
you could do something like
if (authUser === undefined || isLoading) {
return <AuthLoader />;
}
return <LoginComponentContents/>
I would recommend to use for all authentication methods the onAuthStateChanged listener in auth. That way it doesn't matter what method you use. It will give you the user if someon is logged in and null if not. The code looks like this:
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
// User is signed in.
} else {
// No user is signed in.
}
});
Use that listener to define the state of your auth (if a user is signed in or not). You can also persiste the data in your state menegement to awoid flickering on page reloads. You can use the same method for email/password login. That way you have a single and simple solution for all Firebasse authentication methods.
For the time you await the Google or other provider redirect login I would recommend to set a loading flag and show a circular loading indicator. The login could always fail. I would not recommend to show pages that require a signed in user untill you get the response from authStateChanged as expected.
For Firebase v9 and above:
If using an AuthContext file, you can define your signInWithRedirect and getRedirectResult functions. Then, import those functions into your Signup page.
AuthContext:
//Log in user with provider. Redirects away from your page.
async function loginGoogle() {
await signInWithRedirect(auth, provider);
return
}
//Checks for provider login result, then navigates
async function getRedirect(){
const result = await getRedirectResult(auth);
if (result) {
navigate('/')
}
}
In your Signup page, call the login function on button click
//Sign in with Google.
async function handleGoogleLogin(e) {
e.preventDefault()
try {
setError('')
await loginGoogle()
} catch(error) {
setError('Failed to log in')
console.log(error)
}
}
Then, just place the getRedirect() function in your Signup component. This function will run when the page reloads from the google redirect, thus sending your user to the desired page.
//Checks for Google Login result.
getRedirect();
For me, it only worked when using this 2-step approach because when the provider redirect occurs, the async function appears to not finished as expected. So loginWithRedirect in one step, then getRedirectResult and navigate in a second step.

How to redirect user back to initially-requested page after authentication with React-Router v6?

I have a situation where, if a user isn't authenticated, they get redirected to the login page.
Once the user logs in, they get sent back to the main page.
This is a pretty typical situation with React, but I'm wondering how I can redirect the user back to a certain page after they authenticate.
Suppose the user tries to access /app/topics, which would be a private route. They would get redirected to /, where they have to authenticate. Afterwards, they get redirected to /app/about once they authenticated.
How can I ensure that the user gets redirected back to /app/topics instead?
The About component would look something like,
const About = ({ user }) => {
const navigate = useNavigate();
React.useEffect(() => {
if (!user) navigate("/");
}, [user]);
return (
<div>
<h2>About</h2>
</div>
);
};
export default About;
And Home (or the 'login page') would look like this,
const Home = ({ user, setUser }) => {
const navigate = useNavigate();
React.useEffect(() => {
if (user) navigate("/app/about");
}, [user]);
return (
<div>
<h2>Login</h2>
<input />
<button onClick={() => setUser(1)}>login</button>
</div>
);
};
export default Home;
I'm aware the this line,
if (user) navigate("/app/about");
Is why the user gets redirected to About upon authenticating, but I'm wondering how I can change this up, so that the user is redirected back to Topics.
I've tried a combination of different approached. The most promising thing that I've tried was saving the requested uri into my Redux state. This cause issue with my existing code, however.
I've also tried saving state with Navigate or useNavigate.
If I recall correctly, React-Router v5 had a redirect prop or something of the sort, that redirected the user back to a certain page.
I would just fallback to good old query parametr in url, just upon redirecting to login page, put query param, from or something in url, and upon successfull login do the redirect, this has the huge advatage that if you take him to different page or for some reason he has to reload page, he keeps this info.
React router v6 documentation provides an exemple that answers you requirements, here is their sandbox.
They use the from property of location's state:
function LoginPage() {
let navigate = useNavigate();
let location = useLocation();
let auth = useAuth();
let from = location.state?.from?.pathname || "/";
function handleSubmit(event: React.FormEvent<HTMLFormElement>) {
event.preventDefault();
let formData = new FormData(event.currentTarget);
let username = formData.get("username") as string;
auth.signin(username, () => {
// Send them back to the page they tried to visit when they were
// redirected to the login page. Use { replace: true } so we don't create
// another entry in the history stack for the login page. This means that
// when they get to the protected page and click the back button, they
// won't end up back on the login page, which is also really nice for the
// user experience.
navigate(from, { replace: true });
});
}

React with react-redux-firebase isLoaded is true and isEmpty is seemingly false, yet firebase.auth().currentUser is null - what could be the cause?

so I might have difficulty explaining this issue I am having, which I am not able to reproduce consistently. I have a React app on which I am using react-redux-firebase and that I thought I was successfully implementing to keep track of the user session.
My App.js file has the following bit or routing code as a sample (using react-router-dom):
<Route
path="/signin"
render={() => {
if (!isLoaded(this.props.auth)) {
return null;
} else if (!isEmpty(this.props.auth)) {
return <Redirect to="/posts" />;
}
return <Signin />;
}}
/>
This works correctly. I go to Signin component when user is not logged in or Posts when user is logged in. In Signin component I have this bit of logic that happens:
// sign the user in
this.props.firebase.login({
email: user.email,
password: user.password
}).then(response => {
// detect the user's geolocation on login and save
if (isLoaded(this.props.auth)) {
const navigator = new Navigator();
navigator.setGeoLocation(this.props.firebase);
}
// redirect user to home or somewhere
this.props.history.push('posts');
})
I am importing isLoaded like so:
import { firebaseConnect, isLoaded } from 'react-redux-firebase';
the condtional works fine, the user is logged in and then the isLoaded conditional happens - this is where the problem arises. With isLoaded true I would assume that the user and all the redux-firestore user properties are ready for use....but that is sometimes not the case. In navigator.setGeoLocation call I have this:
setGeoLocation(propsFirebase, cb) {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition((position) => {
propsFirebase.auth().currentUser
.getIdToken(/* forceRefresh */ true)
.then((idToken) => {
...
});
}
)
}
}
At this point, propsFirebase.auth().currentUser is sometimes null (this originates in the parameter passed in navigator.setGeoLocation(this.props.firebase);). If I try the signin in all over again, then it works. I am not able to find any consistent way of reproducing.
I have noticed this in other components too. I am not sure if this is an issue that happens when my computer goes to sleep and I should restart the whole React process or what? has anyone seen similar issues? If so, what could I possibly be missing during checking user state in the routing?
If more code is necessary, let me know...
currentUser will be null with the user is not signed in. It will also be null when a page first loads, before the user's token has been loaded and a User object is available. You should use an auth state observer to get the User object if you want to act immediately after it is loaded asynchronously after page load.
firebase.auth().onAuthStateChanged((user) => {
if (user) {
// User is signed in, see docs for a list of available properties
// https://firebase.google.com/docs/reference/js/firebase.User
var uid = user.uid;
// ...
} else {
// User is signed out
// ...
}
});
You might also want to read for more detail: Why is my currentUser == null in Firebase Auth?

Adding reset password functionality to react / redux login functionality

I used the following login with react/redux tutorial to build a signup / signin functionality into my React app, however I did not realize until recently that I now also need a reset-password / forgot-password functionality.
This feature is not a part of the tutorial at all, and I am simply wondering if anybody has any suggestions as to how I can go about this?
Let me know if I can share any info about my app that will help with this, or if there's a better place to post this type of question. I'm holding off on sharing more on the app as I think it's redundant given the info in the tutorial is nearly exactly how my signup / signin is setup.
Thanks!
After the user enters the proper credentials that you state (usually username, email, or both)
Make an api call to your backend that creates a password reset token. Store it in the database and, in one form or another, associate it with the user (usually it's the same database entry).
Send an email to the user with a link that has the password reset token embedded into it. Have a route in your react-router routes that will handle the url you link to.
Have the route mount a component that has a componentDidMount, which takes the token and makes an api to the backend to validate the token.
Once validated, open a ui element in the react component that allows the user to set a new password
Take the new password, password confirmation, and reset token and make an api call to the backend to change the password.
Delete the reset token in the backend after successful password change
// in your routes file
<Route path="/password_reset/:token" component={PasswordResetValidator}/>
//
class PasswordResetValidator extends React.Component {
state = {password: '', passwordReset: '', isValidated: false}
async componentDidMount() {
const response = await validatePasswordResetToken(this.props.token)
if (response.ok) {
this.setState({ isValidated: true })
} else {
// some error
}
}
handleSubmit = () => {
const { token } = this.props
const { password, passwordReset } = this.state
sendPasswordResetData({password, passwordReset, token})
// probably want some confirmation feedback to the user after successful or failed attempt
}
render() {
if(this.state.isValidated) {
return (
<div>
<input />
<input />
<button onClick={this.handleSubmit}>Set new password</button>
<div>
)
}
return // something while token is being validated
}
}
Obviously you need to make your own text input handlers. You should also have error handling, and good ui feedback to the user. But ultimately, that's all at your discretion.
Best of luck

Resources