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>