Search code examples
reactjsauth0

How to persist login through browser refresh using @auth0/auth0-spa-js in react


In my react application I have configured auth0 using @auth0/auth0-spa-js library. Authentication works, but when browser refresh I need to authenticate again. This is not expected behavior.

The code is bellow:

import React, { Component } from "react";
import createAuth0Client from "@auth0/auth0-spa-js";
import Auth0Client from "@auth0/auth0-spa-js/dist/typings/Auth0Client";
import { Auth0Context } from "../../utils/Contexts";
import { IUserCredential } from "../../utils/Structures";

interface state {
  isAuthenticated: boolean;
  user: IUserCredential;
  auth0Client: Auth0Client;
  loading: boolean;
  popupOpen: boolean;
}

interface props {
  onRedirectCallback(appState?: any): void;
  domain: string;
  client_id: string;
  redirect_uri: string;
  prompt?: 'none' | 'login' | 'consent' | 'select_account';
}


export class Auth0Provider extends React.Component<props, state>{

  constructor(props: props) {
    super(props);
  }

  componentDidMount() {
    this.updateComponent();
  }

  async updateComponent() {
    console.log('in updateComponent');
    const DEFAULT_REDIRECT_CALLBACK = () =>
      window.history.replaceState({}, document.title, window.location.pathname);

    let { onRedirectCallback = DEFAULT_REDIRECT_CALLBACK, children, ...initOptions } = this.props;
    //id_token_hint
    const auth0FromHook = await createAuth0Client(initOptions);

    if (window.location.search.includes("code=")) {
      const { appState } = await auth0FromHook.handleRedirectCallback();
      onRedirectCallback(appState);
    }

    const isAuthenticated = await auth0FromHook.isAuthenticated();

    let user = {} as IUserCredential;

    if (isAuthenticated) {
       user = await auth0FromHook.getUser();
    }

    this.setState({
      auth0Client: auth0FromHook,
      isAuthenticated:isAuthenticated,
      user:user,
      loading: false
    });
  }

  loginWithPopup = async (params = {}) => {
    this.setState({
      popupOpen: true
    })
    try {
      await this.state.auth0Client.loginWithPopup(params);
    } catch (error) {
      console.error(error);
    } finally {
      this.setState({
        popupOpen: false
      })
    }

    const user = await this.state.auth0Client.getUser();
    this.setState({
      user: user,
      isAuthenticated: true
    })

  };

  handleRedirectCallback = async () => {
    this.setState({
      loading: true
    });

    if (this.state.auth0Client) {
      await this.state.auth0Client.handleRedirectCallback();
      const user = await this.state.auth0Client.getUser();
      this.setState({
        loading: false,
        isAuthenticated: true,
        user: user
      })
    }
  };

  private getContextVaules() {

    let contextValues = {
      ...this.state,
      loginWithPopup:this.loginWithPopup,
      handleRedirectCallback:this.handleRedirectCallback,
      getIdTokenClaims: (...p: any) => (this.state.auth0Client as Auth0Client).getIdTokenClaims(...p),
      loginWithRedirect: (...p: any) => (this.state.auth0Client as Auth0Client).loginWithRedirect(...p),
      getTokenSilently: (...p: any) => (this.state.auth0Client as Auth0Client).getTokenSilently(...p),
      getTokenWithPopup: (...p: any) => (this.state.auth0Client as Auth0Client).getTokenWithPopup(...p),
      logout: (...p: any) => (this.state.auth0Client as Auth0Client).logout(...p)
    };

    return contextValues;
  }

  render() {
    return (
      <Auth0Context.Provider value={this.getContextVaules()} >
        {this.props.children}
      </Auth0Context.Provider>
    );
  }

}

I have read the silent authentication guid but did not get understand the procedure.
I have passed prompt=none as argument parameter in options of createAuth0Client() method but got error in callback url.


Solution

  • I have solved my problem by changing universal login from class to new