Auth0 Lock with NextJS User persistence

Hello,

I have a project that uses NextJS and auth0-lock. The reason to use auth0-lock is that we had to add some additional fields to the registration form. In order to persist the user session we are using the lock.checkSession method. I see that this method requires options parameter, but I have noticed that if we provide it with just an empty object it still works for the currently logged in user.

Now my question is, are there are problems with this approach. I have seen many posts where people keep their access_token in the localStore, but I am not sure if that is a good idea.

Please let me know if there are any security vulnerabilities or issues with our approach.

Here is the code.

type Props = {
  login: () => void;
  logout: () => void;
  user: Auth0UserProfile | undefined;
};

export const AuthContext = createContext<Props>({
  login: () => {},
  logout: () => {},
  user: undefined,
});

const AuthContextProvider = ({ children }: { children: ReactNode }) => {
  const [lock, setLock] = useState<Auth0LockStatic | undefined>(undefined);
  const [user, setUser] = useState<Auth0UserProfile | undefined>(undefined);
  const didInitialize = useRef(false);
  // TODO: add loading flag

  const checkSession = (lock: Auth0LockStatic) => {
    lock?.checkSession({}, (error, authResult) => {
      if (error) {
        setUser(undefined);
      }
      if (authResult) {
        lock.getUserInfo(authResult.accessToken, (_, profile) => {
          setUser(profile);
        });
      }
    });
  };

  useEffect(() => {
    if (didInitialize.current) {
      return;
    }

    didInitialize.current = true;
    const lock = new Auth0Lock(
      process.env.NEXT_PUBLIC_AUTH0_CLIENT_ID as string,
      process.env.NEXT_PUBLIC_AUTH0_DOMAIN as string,
      {
        auth: {
          redirect: true,
          sso: false,
          responseType: 'token id_token',
          redirectUrl: `${window.location.origin}/auth/callback`,
        },
        avatar: null,
        autofocus: true,
        autoclose: true,
        showTerms: true,
        mustAcceptTerms: true,
        loginAfterSignUp: true,
        additionalSignUpFields: [
          {
            type: 'checkbox',
            name: 'signedUpForNewsletter',
            placeholder: 'Sign me up for your monthly newsletter',
            prefill: 'false',
          },
        ],
        languageDictionary: {
          title: 'Please Login or Create Account',
          loginLabel: 'Login',
          signUpLabel: 'Register',
          forgotPasswordAction: 'Forgot password',
        },
        theme: {
          logo: '/logo.png',
        },
      }
    );

    lock.on('signin submit', () => {
      LocalStorageService.setItem('redirectUrl', window.location.pathname + window.location.search);
    });

    lock.on('signup submit', () => {
      LocalStorageService.setItem('redirectUrl', window.location.pathname + window.location.search);
    });

    setLock(lock);
    checkSession(lock);
  }, []);

  const login = useCallback(() => {
    lock?.show();
  }, [lock]);

  const logout = useCallback(() => {
    setUser(undefined);
    LocalStorageService.setItem('redirectUrl', window.location.pathname + window.location.search);
    lock?.logout({
      returnTo: `${window.location.origin}/auth/callback`,
    });
  }, [lock]);

  const value = useMemo(
    () => ({
      user,
      login,
      logout,
    }),
    [user, login, logout]
  );

  return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
};

export default AuthContextProvider;

export const useAuthContext = () => useContext(AuthContext);
1 Like

Hello,

Any movement on this?
We are building an ecommerce project and this question is very important for us

Hello, any news on the topic?