Vue 3 - Cannot get Widget to launch

I am updating a Vue2 to Vue 3/Vite (not Vue CLI) application, and am having issues getting the Vue framework to redirect to the widget. Using the Classic Flow.

I am following the updated Vue 3 samples. It just seems to skip the calling of or rendering of the Widget.

The issues seems to be when the ‘/’ route is encountered, the Login.vue component is rendered, but the

          <div :id="okta-signin-container"></div>

never gets fired/called/whatever the right term is here in Login.vue .

This was working for a minute - and now, it’s not. I’m working hard to find what I’m doing that is likely stupid, but I’m too close to see it. Thanks for any help.

Code:

*********************** main.js ***********************

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import OktaVue from '@okta/okta-vue'

import { oktaAuth } from './okta';

// 2023.06.24 Removed - this is done in okta/index.js
//const oktaAuth = new OktaAuth(authConfig.oidc);

const app = createApp(App)
    .use(router)
    .use(OktaVue, { 
        oktaAuth,
        onAuthRequired: () => {
            router.push('/login')
         },
         onAuthResume: () => {
            router.push('/login')
          }
        })
    //Added to make v-focus directive work on vue templates
    .directive( 'focus', {
        // When the bound element is inserted into the DOM...
        mounted: function (el) {
            // Focus the element
            el.focus()
        } 
    })
    .mount('#app');

*********************** router/index.js ******************

import { createRouter, createWebHistory } from 'vue-router'

// 2023.05.26 Added the two lines below to reflect new Okta signing process
import { LoginCallback, navigationGuard } from '@okta/okta-vue'

import Login from '@/components/Login.vue'
import StoreTips from '../views/StoreTips.vue';
import StoreHoursRTI from '../views/StoreHoursRTI.vue';
import StoreHoursDL from '../views/StoreHoursDL.vue';
import Payroll from '../views/Payroll.vue';
import SalesLedger from '../views/SalesLedger.vue';
import Config from '../views/Config.vue';

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [
    {
      path: '/',
      name: 'login',
      component: Login,
    },
    {
      path: '/login',
      component: Login ,
    },
    {
      // 2023.05.26 New Callback route for Okta
      path: '/login/callback',
      component: LoginCallback
    },
    {
      path: '/logout',
      beforeEnter (to, from, next) {
        Auth.logout();
        next('/');
      }
    },
    {
      path: '/help',
      name: 'help',
      //component: Help,
      // route level code-splitting
      // this generates a separate chunk (About.[hash].js) for this route
      // which is lazy-loaded when the route is visited.
      component: () => import('../views/Help.vue'),
      meta: {
        requiresAuth: true
      }
    },
    {
      //DEBUG TEMPORARILY CHANGED REQUIRESAUTH TO FALSE
      path: '/about',
      name: 'about',
      // route level code-splitting
      // this generates a separate chunk (About.[hash].js) for this route
      // which is lazy-loaded when the route is visited.
      component: () => import('../views/About.vue'),
      meta: {
        requiresAuth: false
      }
// .... other routes removed for brevity
    }
  ]
})
// Due to navigation guards mixin issue in vue-router-next, navigation guard logic need to be added manually
router.beforeEach(navigationGuard)

export default router

*********************** app.vue ***********************

<template>
  
  <div id="app">
    <!--<keep-alive>
        <template v-if="authenticated">
            <NavBar @user-logout="logout()">
            </NavBar>
        </template>
    </keep-alive> 
   -->

   <!-- DEBUGGING VERSION -->
    <keep-alive>
            <NavBar @user-logout="logout()">
            </NavBar>
    </keep-alive>
   
    <!-- SHOULD BE WORKING VERSION -->
    <!-- router-view inserts the router page destination here --> 
    <!-- VUE3 Version where router-view cannot be inside keep-alive -->
   <!-- $route.matched.length is being used for the Nav-Bar routing-->
    <template v-if="$route.matched.length"> 
        <router-view v-slot="{ Component }"  >
          <keep-alive>
            <component :is="Component" v-bind:authenticated="authenticated" />
          </keep-alive>
        </router-view>
    </template>


    <!-- PRIOR VERSION VUE2 that worked
      <template v-if="$route.matched.length">
            <keep-alive>
                <router-view v-bind:authenticated="authenticated"></router-view>
            </keep-alive>
        </template>
    -->

  </div>
</template> 


<script>

import { RouterLink, RouterView } from 'vue-router';

// Locally scope header component to App.vue
import NavBar from "./components/Navbar.vue";

export default {
        name: 'app',
        components: {
            NavBar
        },
        data() {
            return {
                navComp: "AppComp",
                // authenticated property for lower level components to view
                authenticated: false,
            }
        },
        async created() {
            // On creation, check for auth status
            await this.isAuthenticated();
            // Subscribe to the authStateManager to check for auth changes
            this.$auth.authStateManager.subscribe(this.isAuthenticated);
            },
        watch: {
            // Everytime the route changes, check for auth status
            '$route': 'isAuthenticated'
        },
        methods: {
            async isAuthenticated () {
                this.authenticated = await this.$auth.isAuthenticated()
            },
            async logout () {
                await this.$auth.signOut()
            }
        }
    }

</script>

<style>

    * {
        font-family: 'Work Sans', sans-serif;
        border-radius: 3px !important;
    }
    body {
        background-color: aliceblue;
    }
</style>

*********************** okta/index.js ***********************

import OktaSignIn from '@okta/okta-signin-widget'
import { OktaAuth } from '@okta/okta-auth-js'

const BASEURL = 'https://dev-xxxxx.okta.com'
const ISSUER = import.meta.env.VITE_APP_ISSUER || "https://dev-xxxxxx.okta.com/oauth2/default";
const SPA_CLIENT_ID = import.meta.env.VITE_APP_SPA_CLIENT_ID || "xxxxxxxx";
const CALLBACK_PATH = import.meta.env.VITE_APP_CALLBACK_PATH || window.location.origin + '/login/callback';
const SCOPES = ['openid', 'profile', 'email'];
const OKTA_TESTING_DISABLEHTTPSCHECK = import.meta.env.VITE_APP_OKTA_TESTING_DISABLEHTTPSCHECK || false;


const oktaSignIn = new OktaSignIn({
  baseUrl: BASEURL,
  clientId: SPA_CLIENT_ID,
  redirectUri: 'http://localhost:5173/login/callback',
  useClassicEngine: true, // Set to true to use the Classic Sign In Widget on your custom login page
  authParams: {
    pkce: true,
    issuer: ISSUER,
    display: 'page',
    scopes: SCOPES,
    testing: {
        disableHttpsCheck: OKTA_TESTING_DISABLEHTTPSCHECK
        }
    }
});
const reURI = window.location.origin;

const oktaAuth = new OktaAuth({
  issuer: ISSUER,
  clientId: SPA_CLIENT_ID,
  redirectUri: reURI + '/login/callback',
  scopes: ['openid', 'profile', 'email'],
})

export { oktaAuth, oktaSignIn };

*********************** Login.vue ***********************

<template>
  <div>
      <div :class="login" v-if="!authenticated">
          <h3>Login</h3>
          <div :id="okta-signin-container"></div>
      </div>
      <div v-else :class="login">
          <h4>Welcome! You are logged in. </h4>
          <h5>Select an option above.</h5>
          <br>
          <h6>See what's new in the <a href="/about">About screen</a></h6>
          <h6>Read how to use this site in the <a href="/help">Help screen</a></h6>
          
      </div>
  </div>
</template>

<script>
import {oktaSignIn} from '../okta'

export default {
  name: 'Login',
  props: [
    'authenticated'
  ],
  data() {
    return {}
  },
  mounted: function () {
    //nextTick waits until all child components have been rendered
    this.$nextTick(function () {
      oktaSignIn.showSignInAndRedirect(
        { el: '#okta-signin-container' },
      )
    })
  },
  unmounted () {
    // Remove the widget from the DOM on path change
    oktaSignIn.remove()
  }
}
</script>

Answering my own question here, kind of.

When I was using the colon shorthand for v-bind like I posted in the original question with a colon in front of the ‘id’:

<div :id="okta-signin-container"></div>

Vue 3/ Vite did not recognize the as having a valid name. In the runtime debugger using Vue Devtools, it showed “NaN” IIRC.

But when I removed the colon, thusly:

<div id="okta-signin-container"></div>

the behavior changed and it actually redirected to the Okta Widget and rendered the widget correctly.

Learned on stackoverflow.com that I was trying to bind a dynamic variable name to the

when I was really needing to set a simple id to it. So, I should have been using the normal HTML id attribute. Duh.