Redirect client back to previous page after authentication

programmatically change Auth0 callback link after authenticating using Redux

Fri, 02 Nov 2018

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);
Loading...
Edward Beazer

Edward Beazer - I just like to build shit. Sometimes I get stuck for hours, even days while trying to figure out how to solve an issue or implement a new feature. Hope my tips and tutorials can save you some time.