AxaFrance / oidc-client

Light, Secure, Pure Javascript OIDC (Open ID Connect) Client. We provide also a REACT wrapper (compatible NextJS, etc.).
MIT License
578 stars 157 forks source link

tryKeepExistingSessionAsync and loginCallbackAsync refresh loop in Vue #1426

Open RonanRobineau opened 1 month ago

RonanRobineau commented 1 month ago

Issue and Steps to Reproduce

On my Vue app, using the vanilla oidc client, I have a loop of refresh when I try to use the loginCallbackAsync or use the tryKeepExistingSessionAsync.

Here is the flow: I got a Pinia store, and I instantialize the oidc client here (with getOrCreate), and 2 actions: login and callback. Login works fine, but the loginCallbackAsync creates a reload of the page, without any eror (it is un an onMounted function). Same with tryKeepExistingSessionAsync, I have it on my root component, and it juste reload the page, again and again.

I tried my configuration with the oidc-client-demo, and it works fine.

guillaume-chervet commented 1 month ago

Hi @RonanRobineau , do you have a full sample of code? Bellow the main react component : https://github.com/AxaFrance/oidc-client/blob/main/packages/react-oidc/src/OidcProvider.tsx I am pretty sure it should look pretty the same.

I can try to build a vie implementation if you need it.

RonanRobineau commented 1 month ago

Hi @guillaume-chervet , I managed to make it work based on the react component indeed. But I think making a wrapper component might not be a Vue standard, let me explain what I did :

Making this creates the hard reload. Here is my OIDCHandler.vue component, wrapping my router-view :

<script setup>
import {OidcClient} from '@axa-fr/oidc-client'
import { ref } from 'vue';

const configuration = {
    client_id: 'xxxxx',
    redirect_uri: window.location.origin + '/oidc/callback',
    silent_redirect_uri: window.location.origin + '/oidc/silent-callback',
    scope: 'openid',
    authority: 'xxxxx',
    refresh_time_before_tokens_expiration_in_second: 40,
    service_worker_relative_url: '/OidcServiceWorker.js',
    service_worker_only: true,
  };

  const href = window.location.href;

  const token = ref(null)
  const vanillaOidc = OidcClient.getOrCreate(() => fetch)(configuration);

  vanillaOidc.tryKeepExistingSessionAsync().then(() => {
    token.value = vanillaOidc.tokens;
    if (token.value) {
      window.document.getElementById('logout').addEventListener('click', logout);
    } else {
      window.document.getElementById('login').addEventListener('click', login);
    }
  });

  function logout() {
    vanillaOidc.logoutAsync();
  }
  function login() {
    vanillaOidc.loginAsync('/');
  }
  if (href.includes(configuration.redirect_uri)) {
    vanillaOidc.loginCallbackAsync().then(() =>   document.location = localStorage.getItem('lastUrl'))
  }
</script>

<template>
  <slot />
</template>

This is quite a simple one, I took the wrapper idea from the react-oidc and applied the vanillajs behaviour, but it does the job (except that you have to create 2 button with id="login" and id="logout". I don't have the time to create a fully fonctional component like the react one, but I might add some stuff on it and create a PR in order to make it easier for Vue users