Redirect client back to previous page after authentication
programmatically change Auth0 callback link after authenticating using Redux
You can view these tutorials to set up Redux in order to do this example
Code
After setting up redux in your application you want to create a callback action.
Actions
export const setCallbackLink = callbackLink => ({ type: 'SET_CALLBACK_LINK', callbackLink });
createStore
import { createStore as reduxCreateStore } from 'redux';
const reducer = (state, action) => {
if (action.type === 'SET_CALLBACK_LINK') {
return Object.assign({}, state, { callbackLink: action.callbackLink });
}
return state;
};
const initialState = {
callbackLink: '/',
};
const createStore = () => reduxCreateStore(reducer, initialState)
export default createStore;
Login Component
Our login component changes a little now. I have my component setup as a separate component that handles all the login task. If you have yours setup differently, all you need to do is wrap it around a Redux Connect and import your actions. When a user clicks on the button, we will store the current browser location into our redux store. I am using Gatsby in this example and pass the location as a props to my login button
import React, { Component } from 'react';
import { Login } from 'auth/Auth';
import { connect } from 'react-redux';
import { setCallbackLink } from '../actions';
const mapStateToProps = ({ callbackLink }) => ({ callbackLink });
const mapDispatchToProps = dispatch => ({
setCallbackLink: callbackLink => dispatch(setCallbackLink(callbackLink)),
});
class LoginButton extends Component {
constructor(props) {
super(props);
this.login = this.login.bind(this);
}
componentDidMount() {
const { setCallbackLink: setLink, pathname } = this.props;
setLink(pathname);
}
login() {
Login();
const { setAuthentication } = this.props;
setAuthentication();
}
render() {
return (
<button onClick={this.login}>
Log In
</button>
);
}
}
export default connect(mapStateToProps, mapDispatchToProps)(LoginButton);
Callback
Our callback method also uses a similar convention that the login button uses. We just need to wrap our component with a Redux Connect. After that we grab the stored location from our Redux store. In my application, the index page just serves as a login, due to that I redirect the user to the search page instead of back to the index page. You can forgo that if/else statement.
import React, { Component } from 'react';
import loading from 'assets/images/loading.svg';
import { navigate } from 'gatsby';
import { handleAuthentication } from 'auth/Auth';
import { connect } from 'react-redux';
import { setCallbackLink } from '../actions';
const mapStateToProps = ({ callbackLink }) => ({ callbackLink });
const mapDispatchToProps = dispatch => ({
setCallbackLink: callbackLink => dispatch(setCallbackLink(callbackLink)),
});
class Callback extends Component {
componentDidMount() {
const { callbackLink } = this.props;
handleAuthentication();
setTimeout(() => {
if (callbackLink === '/') {
navigate('/search');
} else {
navigate(callbackLink);
}
}, 1500);
}
render() {
return (
<div style={{
position: 'absolute',
display: 'flex',
justifyContent: 'center',
height: '98vh',
width: '98vw',
top: 0,
bottom: 0,
left: 0,
right: 0,
backgroundColor: 'white',
}}
>
<img src={loading} alt="loading" />
</div>
);
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Callback);