auth0/auth0-vue

Access to isAuthenticated in router

donniekerr opened this issue · 6 comments

Describe the problem

Related to my last question about Ionic-Vue-Capacitor. Given the redirect had to be replaced by using Capacitor Browser plugin, I can no longer use authguard in beforeEnter in my router file. It wants to redirect to the external browser.
I tried accessing isAuthenticated in the router like this code below, but it throws the same error related to not being inside of a component's setup function.

/const { isAuthenticated } = useAuth0();
`router.beforeEach(async (to, from) => {

if (
// make sure the user is authenticated
!isAuthenticated &&
to.name !== 'Login'
) {
// redirect the user to the login page
console.log('redirect to login')
return { name: 'Login' }
}
}) `
I also tried passing a to: into the authguard so it goes to /login, but I couldn't get the right syntax for the to parameter to make it work. Not sure if that will work?

What was the expected behavior?

I need a recommendation on how to protect routes that is compatible with the workaround of using auth0-vue in a Capacitor app. Is there a way to access isAuthenticate outside of a component setup? Or is there a better way?

Reproduction

Can the behavior be reproduced using the Vue SDK Playground?

Environment

  • Version of auth0-vue used:
  • Version of vue used:
  • Which browsers have you tested in?
  • Other modules/plugins/libraries that might be involved:

I think for now, you would need to roll your own guard based on ours, if you would modify our code to below, it should work:

async function createGuardHandler(client: Auth0VueClient, to: RouteLocation) {
  const fn = async () => {
    if (unref(client.isAuthenticated)) {
      return true;
    }

    const url = await client.buildAurhorizeUrl({
      appState: { target: to.fullPath }
    });
    
    await Browser.open({ url });

    return false;
  };

  if (!unref(client.isLoading)) {
    return fn();
  }

  await watchEffectOnceAsync(() => !unref(client.isLoading));

  return fn();
}

export function createAuthGuard(app: App) {
  return async (to: RouteLocation) => {
    const auth0 = app.config.globalProperties[AUTH0_TOKEN] as Auth0VueClient;

    return createGuardHandler(auth0, to);
  };
}

export async function authGuard(to: RouteLocation) {
  const auth0 = unref(auth0Client);

  return createGuardHandler(auth0, to);
}

We might want to see how we can improve it here, but will hold of as we are working on a v2 of auth0-spa-js, which is the core SDK used here. In that new major, we are going to rework the way you would integrate with Ionic slightly, which might make things easier here as well. So for the time being, you'll need to use a guard like above.

ok. Sounds good. Look forward to new version. Thank you!

@frederikprijck any update on this ?

@Kavan72 You should be able to use the following factory to create the guard and make it use Capacitor's browser.

createAuthGuard({
  redirectLoginOptions: {
    openUrl(url) {
      Browser.open(url);
    }
  }
})

Let me know if that works.

@frederikprijck i want to use something like this

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [
    ...setupLayouts(routes),
  ],
})

router.beforeEach(to => {
  const { isAuthenticated } = useAuth0()

  if (!isAuthenticated)
    return { name: 'login' }
})

but useAuth0() is returing undefined

@Kavan72 useAuth0 is not supposed to be used outside components, just like any other hooks in vue.

Have a look at our guard for how to communicate with the SDK in a guard.