logto-io / js

🤓 Logto JS SDKs.
https://docs.logto.io/quick-starts/
MIT License
49 stars 36 forks source link

How to obtain accessToken in client-side when SSR is disabled? #747

Open cuixiaorui opened 1 week ago

cuixiaorui commented 1 week ago

Description

I am currently using Logto with a Nuxt.js application where SSR (Server-Side Rendering) is disabled. My goal is to obtain an accessToken in the client-side environment, particularly for initializing TRPC clients with authentication headers.

Issue

The useLogtoClient composable, which is designed to access the Logto client instance, does not seem to work in a client-side context when SSR is turned off. This poses a challenge in securely fetching and handling the accessToken required for authenticated requests.

Current Approach

I have attempted to fetch the accessToken within a defineNuxtPlugin setup, expecting it to operate under a client-side context when SSR is disabled. However, the limitation around useLogtoClient being unavailable in the client-side context has led to difficulties in achieving this.

export default defineNuxtPlugin(async () => {
  const { accessToken } = await setupToken();

  const client = createTRPCNuxtClient<AppRouter>({
    transformer: superjson,
    links: [
      errorHandlingLink,
      httpBatchLink({
        url: "/api/trpc",
        async headers() {
          return {
            authorization: `Bearer ${accessToken.value}`,
          };
        },
      }),
    ],
  });

  return {
    provide: {
      client,
    },
  };
});

async function setupToken() {
  const config = useRuntimeConfig();
  const logto = useLogtoClient();
  const accessToken = useState<string | undefined>("access-token");

  await callOnce(async () => {
    if (!logto) {
      throw new Error("Logto logto is not available");
    }

    if (!(await logto.isAuthenticated())) {
      return;
    }

    try {
      const token = await logto?.getAccessToken(config.logto.resources[0]);
      accessToken.value = token;
    } catch (error) {
      console.error("Failed to get access token", error);
    }
  });

  return {
    accessToken,
  };
}

Questions

  1. Is there an alternative approach or recommended practice for obtaining the accessToken in a client-side only Nuxt.js application using Logto?
  2. Could you provide guidance or examples on how to securely manage and access authentication tokens in a Nuxt.js application where SSR is not utilized?

Additional Context

I appreciate any insights or suggestions you could provide on this matter. Thank you! @gao-sun

ysemennikov commented 1 week ago

Hi @cuixiaorui, I was also interested in this, and I would suggest to use @logto/vue instead of @logto/nuxt. You can connect the Vue SDK using defineNuxtPlugin, something like this:

import { type LogtoConfig, createLogto } from '@logto/vue';

export default defineNuxtPlugin({
  name: 'logto-vue',
  parallel: true,
  setup(nuxtApp) {
    const runtimeConfig = useRuntimeConfig();

    if (!runtimeConfig.public.LOGTO_APP_ID || !runtimeConfig.public.LOGTO_ENDPOINT) {
      throw new Error('NUXT_PUBLIC_LOGTO_APP_ID and NUXT_PUBLIC_LOGTO_ENDPOINT environment variables must be set.');
    }

    const logtoConfig: LogtoConfig = {
      endpoint: runtimeConfig.public.LOGTO_ENDPOINT,
      appId: runtimeConfig.public.LOGTO_APP_ID,
    };
    nuxtApp.vueApp.use(createLogto, logtoConfig);
  },
});

And then use the useLogto composable in your components. I'm not sure whether it will also work in SSR or not, but if you only work with SPA, then it can be an approach for you. However, you should then implement your own sign-in and sign-out routes, as they're not included in @logto/vue.