Looking for a way to make certain pages in Vue3 accessible without authentication using KeyCloak-js

Currently, I am integrating keycloak-js adapter into a Vue 3 Application. The challenge I am facing is with the system's public pages, which prevent me from calling Keycloak immediately. Even though I have set up a button to trigger the login page, the token is not getting stored in the localStorage.

The desired user flow should be: Landing page > Click login button > Redirect to Keycloak login page > Redirect to a page where a request for user roles is made > Obtain user roles and redirect to the appropriate page.

I am encountering an issue where my request requires a token but fails due to the absence of a token or refresh token. Additionally, when attempting a different approach, it gives a TypeError: adapter is undefined error.

Here is my keycloak init function. When I change the onLoad option to check-sso, it returns #error=login_required&state=c7d6d227-5b23-4b21-962a-8e6291545f55, indicating that login-required is functioning correctly for me.

const Login = () => {
    KeyCloakInstance.init({ onLoad: "login-required", checkLoginIframe: true, 
    redirectUri: window.location.origin + "/redirect" })
    .then((authenticated) => {
        console.log("Keycloak Authenticated", authenticated)
        if (authenticated) {
            console.log("Authentication Success")
            KeyCloakInstance.authenticated = true;
        } else {
            console.log("Authentication Failed")
        }

        localStorage.setItem('token', KeyCloakInstance.token as string);
        localStorage.setItem('refreshToken', KeyCloakInstance.refreshToken as string);

    }).catch((err) => {
        console.dir(err);
        console.log("Authentication Failed", err);
    });
}

Below is the guard I created for the routes:

import { getRole } from "@/services/config";
import Keycloak from "keycloak-js";

function guardAuth(to: any, from: any, next: any){
    const hasUser = localStorage.getItem("token");
    const isMeta = "auth" in to.meta;
    const metaAuth = to.meta.auth;

    if(isMeta && metaAuth && !hasUser){
        const keycloakInst = new Keycloak({
            url: "http://localhost:8082/",
            realm: "APP",
            clientId: "live_app"
        });

        keycloakInst.login();
    } else if(isMeta && !metaAuth && hasUser){
        RoleType(hasUser, next);
    } else {
        next();
    }
}

function RoleType(user: any, next: any): void{
    if(getRole() == user.role_portal){
        next('/redirect');
    } else {
        next('/');
    }
}

export { guardAuth };

I have experimented with changing the keycloak init options and creating guards for my routes in order to verify if there is a token present, but they do not seem to be effective. My aim is to establish a flow where some pages are publicly accessible while others are protected by Keycloak.

Answer №1

Incorporating Keycloak into my Vue.js application was a process I carefully set up. Within my app, there are two public pages while the rest remain private and can only be accessed post keycloak authentication.

    import Keycloak from "keycloak-js";
    import useStore from "./store";
    
    const initOptions = {
      realm: import.meta.env.VITE_KEYCLOAK_REALM_NAME,
      clientId: import.meta.env.VITE_KEYCLOAK_CLIENT_ID,
      url: import.meta.env.VITE_KEYCLOAK_SERVER_URL,
      "public-client": true,
      "verify-token-audience": false,
    };
    
    const keycloak = Keycloak(initOptions);
    
    async function initKeycloak() {
      const store = useStore();
    
      await keycloak
        .init({onLoad: "check-sso", redirectUri: import.meta.env.VITE_KEYCLOAK_REDIRECT_URI})
        .then(async (auth) => {
          if (!auth) {
            store.unauthenticate();
          } else {
            await store.authenticate();
            if (keycloak.token) {
              store.token = keycloak.token;
              store.userRoles = keycloak.tokenParsed.realm_access.roles;
              window.localStorage.setItem("keycloakToken", keycloak.token);
            }
          }
        });
      setInterval(() => {
        keycloak
          .updateToken(70)
          .then((refreshed) => {
            if (refreshed) {
              store.token = keycloak.token;
              window.localStorage.setItem("keycloakToken", keycloak.token);
              console.info("Token refreshed" + refreshed);
            } else {
              console.warn(
                "Token not refreshed, valid for " +
                  Math.round(
                    keycloak.tokenParsed.exp +
                      keycloak.timeSkew -
                      new Date().getTime() / 1000
                  ) +
                  " seconds"
              );
            }
          })
          .catch(() => {
            console.error("Failed to refresh token");
          });
      }, 3000);
    }
    
    export async function keycloakLogin() {
      keycloak.login();
    }
    
    // keycloak logout
    var logoutOptions = {redirectUri: import.meta.env.VITE_KEYCLOAK_REDIRECT_URI};
    
    function keycloakLogout() {
      keycloak
        .logout(logoutOptions)
        .then((success) => {
          console.log("--> log: logout success ", success);
        })
        .catch((error) => {
          console.log("--> log: logout error ", error);
        });
    }

Your usage of KeycloakInstance raises some questions; perhaps it's declared elsewhere in the file. In contrast, I simply employ the keycloakLogin method on the landing page where users can sign in due to its public accessibility and existence of a login button.

Upon clicking the login button, the keycloakLogin method executes, directing users to the authorization server. Upon successful validation, it redirects users to the specified redirectUri as outlined in my .env configuration.

I trust this explanation sheds light on the setup process.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Display options based on the value selected in the preceding selection

How can I dynamically display select options in an Angular select based on a previously selected value? Take a look at the code snippet below. Here, I have implemented a conditional display of select options (Target 1/Target 2) based on the value selected ...

Leveraging Vue 2.0 and webpack to integrate components from an npm package

As I venture into setting up a project with webpack and Vue 2.0, I encountered a slight hiccup when trying to incorporate components from npm packages (such as vue-parallax) into my project. Upon installing the package, everything seems to be in place, bu ...

Tips for utilizing boolean values in form appending with Vue.js

I am currently attempting to send availability as a boolean value. However, despite my efforts, it keeps sending false to my database. Here is my code snippet: <input v-model="availability" /> </d ...

Frontend Angular Posting Data to Server

https://i.sstatic.net/6dcPt.png https://i.sstatic.net/uFMuL.png I have two components - one is a form and the other is a dialog with a form. When I click on the dialog with the form and input data, I want to save it first in an in-memory, and then post all ...

Oops! Property 'month' cannot be set on undefined value due to a TypeError

Despite not receiving any errors from Visual Studio Code, I’m encountering an error in Chrome's console. Below is the code snippet from my interfaces.ts file: export interface Data1{ month: string; employeeName: string; date: string; employmentSta ...

What could be causing the global npm package to not be utilized for module dependencies?

My typescript and ts-node are already installed globally. In my package.json file, I have the necessary configurations to run tests with npm test. Everything works fine since ts-node and typescript are installed as local modules. { "name": "two_sum", ...

Implementing multer diskStorage with Typescript

I'm currently in the process of converting a node.js server to TypeScript. Here is what my function looks like in Node: const storage = multer.diskStorage({ destination: function (req, file, cb) { const dir = './uploads/'; ...

A step-by-step guide on accessing the data from an uploaded JSON file in a React application

One exciting feature is the drag and drop component that allows users to add multiple files. However, there seems to be an issue with displaying the content of a JSON file once it's added. Below is the code snippet in question: if (files?.length) ...

Determine whether something has the potential to be a string in TypeScript

I am looking to create a TypeScript type that can identify whether an element has the potential to be a string. This means the element should have the type "string" or "any", but not "number", "boolean", "number[]", "Person", etc. I have experimented wit ...

Sequelize's bulk synchronization process is ineffective

I am facing an issue with getting sequelize.sync() to function properly. When I call sync() for each model definition individually, it works perfectly fine. However, when trying to execute it from the sequelize instance itself, it seems like the registered ...

Incorporating a vanilla JS library (Pickr) into a NuxtJS page component

Recently, I've been experimenting with integrating the Pickr JS library (specifically from this link: [) into my NuxtJS project. To install it, I simply use NPM: npm install @simonwep/pickr In one of my NuxtJS pages - the create.vue page to be exac ...

What is the most effective way to eliminate all values in an object key array except for one specific value?

Currently, I am developing an angular project and have encountered an object with the following structure: const obj = { fruits: ['apple', 'orange', 'None'], nation: ['usa'], city: ['New York', ' ...

Exploring the application of a counter flag within a v-for loop

Is it possible to use a counter flag within a nested v-for loop to keep track of the total number of iterations? Here is an example of my template: <a :href="'#/product/'+list.id" :id="ikeyCounter" v-for="item, ikey in section.list" class="mo ...

In Typescript, it mandates that a string value must be one of the values within the object

There is a constant declaration mentioned below: export const Actions = { VIEW: 'view', EDIT: 'edit', }; Imagine there's a function like this: // Ensuring that the action variable below is always a string with value either ...

Vue 3 has a known issue where scoped styles do not get applied correctly within the content of a <slot> element

Utilizing the Oruga and Storybook libraries for creating Vue 3 components. The code in the Vue file looks like this: <template> <o-radio v-bind="$props" v-model="model"> <slot /> </o-radio> </template ...

What is the purpose of uploading the TypeScript declaration file to DefinitelyTyped for a JavaScript library?

After releasing two JavaScript libraries on npm, users have requested TypeScript type definitions for both. Despite not using TypeScript myself and having no plans to rewrite the libraries in TypeScript, I am interested in adding the type definition files ...

Angular 5 does not allow function calls within decorators

I encountered an issue while building a Progressive Web App (PWA) from my Angular application. When running ng build --prod, I received the following error: ERROR in app\app.module.ts(108,64): Error during template compile of 'AppModule' Fu ...

Retrieve unique elements from an array obtained from a web API using angular brackets

I've developed a web application using .NET Core 3.1 that interacts with a JSON API, returning data in the format shown below: [ { "partner": "Santander", "tradeDate": "2020-05-23T10:03:12", "isin": "DOL110", "type ...

Utilizing Variables in TypeScript to Enhance String Literal Types

Here are my codes: export const LOAD_USERS = 'LOAD_USERS'; export const CREATE_USER = 'CREATE_USER'; export interface ACTION { type: string, payload: any } I am trying to limit the possible values for ACTION.type to either 'L ...

What is the best approach for filtering a nested array in this scenario?

Here is the response I am getting: let m = [ { name: 'Summary', subListExpanded: false, subList: [ ] }, { name: 'Upload', subListExpanded: false, subList: [ ...