Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

isAuthenticated is undefined after reload #64

Closed
cctoni opened this issue Jul 11, 2019 · 9 comments
Closed

isAuthenticated is undefined after reload #64

cctoni opened this issue Jul 11, 2019 · 9 comments

Comments

@cctoni
Copy link

cctoni commented Jul 11, 2019

So i tried to make things work with the described example from the react wrapper, also managed to make things work. The problem we have right now is when reloading the app the isAuthenticated is always undefined. We wrapped the Code inside a AppContext wich provides these things for other components and than loads an AuthenticatedApp or UnauthenticatedApp. When flushing the cache and reload the whole Application everything works, but after hitting reload again the isAuthenticated is always undefined. Maybe someone is having the similiar issues.

Code for App:

const loadAuthenticatedApp = () => import('./authenticated-app');
const AuthenticatedApp = React.lazy(loadAuthenticatedApp);
const UnauthenticatedApp = React.lazy(() => import('./unauthenticated-app'));

interface IPrivateApp {
  path?: string;
}

const App: React.FC<IPrivateApp> = ({ path, ...rest }) => {
  const { isAuthenticated, loginWithRedirect } = useAuth0();

  React.useEffect(() => {
    const fn = async () => {
      console.log(`AUTH STATUS`, isAuthenticated);
      if (isAuthenticated === false) {
        await loginWithRedirect({
          appState: { targetUrl: path },
          redirect_uri: '',
        });
      }
    };
    fn();
  }, [isAuthenticated, loginWithRedirect, path]);

  // React.useEffect(() => {
  //   loadAuthenticatedApp();
  // }, []);

  return (
    <Suspense fallback={<CircularProgress />}>
      {isAuthenticated ? <AuthenticatedApp {...rest} /> : <UnauthenticatedApp />}
    </Suspense>
  );
};

export default App;

And Code for the Provider:

import React, { useState, useEffect, useContext, useLayoutEffect } from 'react';
import createAuth0Client from '@auth0/auth0-spa-js';
import Auth0Client from '@auth0/auth0-spa-js/dist/typings/Auth0Client';

interface Auth0Context {
  isAuthenticated: boolean;
  user: any;
  loading: boolean;
  popupOpen: boolean;
  loginWithPopup(options: PopupLoginOptions): Promise<void>;
  handleRedirectCallback(): Promise<RedirectLoginResult>;
  getIdTokenClaims(o?: getIdTokenClaimsOptions): Promise<IdToken>;
  loginWithRedirect(o: RedirectLoginOptions): Promise<void>;
  getTokenSilently(o?: GetTokenSilentlyOptions): Promise<string | undefined>;
  getTokenWithPopup(o?: GetTokenWithPopupOptions): Promise<string | undefined>;
  logout(o?: LogoutOptions): void;
}
interface Auth0ProviderOptions {
  children: React.ReactElement;
  onRedirectCallback?(result: RedirectLoginResult): void;
}

const DEFAULT_REDIRECT_CALLBACK = () => window.history.replaceState({}, document.title, window.location.pathname);

export const Auth0Context = React.createContext<Auth0Context | null>(null);
export const useAuth0 = () => useContext(Auth0Context)!;
export const Auth0Provider = ({
  children,
  onRedirectCallback = DEFAULT_REDIRECT_CALLBACK,
  ...initOptions
}: Auth0ProviderOptions & Auth0ClientOptions) => {
  const [isAuthenticated, setIsAuthenticated] = useState();
  const [user, setUser] = useState();
  const [auth0Client, setAuth0] = useState<Auth0Client>();
  const [loading, setLoading] = useState(true);
  const [popupOpen, setPopupOpen] = useState(false);

  useEffect(() => {
    const initAuth0 = async () => {
      const auth0FromHook = await createAuth0Client(initOptions);
      console.log(`SET AUTH0`);
      setAuth0(auth0FromHook);

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

      const isAuthenticated = await auth0FromHook.isAuthenticated();

      setIsAuthenticated(isAuthenticated);

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

      setLoading(false);
    };
    initAuth0();
    // eslint-disable-next-line
  }, []);

  const loginWithPopup = async (o: PopupLoginOptions) => {
    setPopupOpen(true);
    try {
      // non null assertion operator - expression to tell the compiler
      // that this could not be null or undefined
      // READ MORE: https://github.com/Microsoft/TypeScript/wiki/What's-new-in-TypeScript#non-null-assertion-operator
      await auth0Client!.loginWithPopup(o);
    } catch (error) {
      console.error(error);
    } finally {
      setPopupOpen(false);
    }
    const user = await auth0Client!.getUser();
    setUser(user);
    setIsAuthenticated(true);
  };

  const handleRedirectCallback = async () => {
    setLoading(true);
    const result = await auth0Client!.handleRedirectCallback();
    const user = await auth0Client!.getUser();
    setLoading(false);
    setIsAuthenticated(true);
    setUser(user);
    return result;
  };
  return (
    <Auth0Context.Provider
      value={{
        isAuthenticated,
        user,
        loading,
        popupOpen,
        loginWithPopup,
        handleRedirectCallback,
        getIdTokenClaims: (o: getIdTokenClaimsOptions | undefined) => auth0Client!.getIdTokenClaims(o),
        loginWithRedirect: (o: RedirectLoginOptions) => auth0Client!.loginWithRedirect(o),
        getTokenSilently: (o: GetTokenSilentlyOptions | undefined) => auth0Client!.getTokenSilently(o),
        getTokenWithPopup: (o: GetTokenWithPopupOptions | undefined) => auth0Client!.getTokenWithPopup(o),
        logout: (o: LogoutOptions | undefined) => auth0Client!.logout(o),
      }}
    >
      {children}
    </Auth0Context.Provider>
  );
};

And the index.tsx:

render(
  <ApolloProvider client={ApolloClient}>
    <Router history={history}>
      <AppProvider>
        <App />
      </AppProvider>
    </Router>
  </ApolloProvider>,
  document.getElementById('root') as HTMLElement,
);
@luisrudge
Copy link
Contributor

Looks like you're checking for isAuthenticated while the SDK is still fetching data from the server. You have to wait loading to be false before doing anything with the sdk:

const { isAuthenticated, loading } = useAuth0();
useEffect(() => {
    const doSomething = async () => {
      console.log(isAuthenticated);
    };
    if (!loading) {
      doSomething();
    }
  }, [loading, getTokenSilently]);

I'll close this issue because it's not related to the SDK itself. If you have more questions, feel free to use https://community.auth0.com/ or open an issue in the sample repo: https://github.com/auth0-samples/auth0-react-samples

@stigmat4j
Copy link

Same problem. Not saving auth session. Even on auth0-react-samples.

@felix-weizman-deel
Copy link

Same here.

@mvanderlee
Copy link

I ran into this, and turns out it's due to using Angular's HashLocationStrategy.
Once I ran it without the hash, it worked fine.
Haven't figured out how to get it working with hash.

@bermichel
Copy link

I had the same problem. After i reload the page i dont want to run createAuth0Client again due to the its duration (30secs aprox). Do you have any suggestion?

@luisrudge
Copy link
Contributor

@kylecase
Copy link

kylecase commented Oct 18, 2019

Your index.tsx needs to be wrapped with <Auth0Provider/> (this is a snippet from their docs):


import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import * as serviceWorker from "./serviceWorker";
import { Auth0Provider } from "./react-auth0-spa";
import config from "./auth_config.json";

// A function that routes the user to the right place
// after login
const onRedirectCallback = appState => {
  window.history.replaceState(
    {},
    document.title,
    appState && appState.targetUrl
      ? appState.targetUrl
      : window.location.pathname
  );
};

ReactDOM.render(
  <Auth0Provider
    domain={config.domain}
    client_id={config.clientId}
    redirect_uri={window.location.origin}
    onRedirectCallback={onRedirectCallback}
>
    <App />
  </Auth0Provider>,
  document.getElementById("root")
);

@mrlubos
Copy link

mrlubos commented Jan 30, 2020

Anyone else struggling with this, also ensure your application does not use the Auth0 development keys for social login!

@matiastucci
Copy link

matiastucci commented Jul 7, 2020

In my case the problem was that I was redirecting before waiting for isLoading. I had this:

<PrivateRoute path="/">
  <Redirect to={{ pathname: "/foo" }} />
</PrivateRoute>

and needed to update my PrivateRoute component to this:

function PrivateRoute({ children, ...rest }) {
  const { isAuthenticated, isLoading } = useAuth0();

  if (isLoading) {
    return null;
  }

  return (
    <Route
      {...rest}
      render={({ location }) =>
      isAuthenticated ? (
          children
        ) : (
          <Redirect
            to={{
              pathname: "/login",
              state: { from: location }
            }}
          />
        )
      }
    />
  );
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants