@josempgon/vue-keycloak
vue-keycloak
A small Vue wrapper library for the Keycloak JavaScript adapter.
This library is made for Vue 3 with the Composition API.
Requirements
- Vue 3.4+
- keycloak-js 18–26
Installation
Using npm:
npm install @josempgon/vue-keycloak
Using yarn:
yarn add @josempgon/vue-keycloak keycloak-js
Using pnpm:
pnpm add @josempgon/vue-keycloak keycloak-js
Use Plugin
Import the library into your Vue app entry point.
import { vueKeycloak } from '@josempgon/vue-keycloak'
Apply the library to the Vue app instance.
const app = createApp(App)
app.use(vueKeycloak, {
config: {
url: 'http://keycloak-server',
realm: 'my-realm',
clientId: 'my-app',
}
})
Configuration
| Object | Type | Required | Description |
|---|---|---|---|
| config | KeycloakConfig |
Yes | Keycloak configuration. |
| initOptions | KeycloakInitOptions |
No | Keycloak init options. |
initOptions Default Value
{
flow: 'standard',
checkLoginIframe: false,
onLoad: 'login-required',
}
User-provided initOptions are merged with the defaults above, so you only need to specify values you want to override.
Dynamic Keycloak Configuration
Use the example below to generate a dynamic Keycloak configuration. In that example the Keycloak adapter is initialized in silent check-sso mode. Be aware that this mode could have limited functionality with recent browser versions (check Modern Browsers with Tracking Protection for additional info).
app.use(vueKeycloak, async () => {
const url = await getAuthBaseUrl()
const silentCheckSsoRedirectUri = `${location.origin}/silent-check-sso.html`
return {
config: {
url,
realm: 'my-realm',
clientId: 'my-app',
},
initOptions: {
onLoad: 'check-sso',
silentCheckSsoRedirectUri,
},
}
})
When using silentCheckSsoRedirectUri, you must serve a silent-check-sso.html file at that path. See the Keycloak documentation for the required file contents.
Use with vue-router
app.use() does not await async plugins, so if you need authentication to complete before the rest of your app setup (e.g. router initialization), call vueKeycloak.install directly and await it:
router/index.js
import { createRouter, createWebHistory } from 'vue-router'
const routes = [ /* Your routes */ ]
const initRouter = () => {
const history = createWebHistory(import.meta.env.BASE_URL)
return createRouter({ history, routes })
}
export { initRouter }
main.js
import { createApp } from 'vue'
import { vueKeycloak } from '@josempgon/vue-keycloak'
import vueKeycloakConfig from './config/vueKeycloak.js'
import App from './App.vue'
import { initRouter } from './router'
const app = createApp(App)
await vueKeycloak.install(app, vueKeycloakConfig)
app.use(initRouter())
app.mount('#app')
If you are building for a browser that does not support Top-level await, you should wrap the Vue plugin and router initialization in an async IIFE:
(async () => {
await vueKeycloak.install(app, vueKeycloakConfig);
app.use(initRouter());
app.mount('#app');
})();
Use Token
A helper function is exported to manage the access token.
getToken
| Function | Type | Description |
|---|---|---|
| getToken | (minValidity?: number) => Promise<string> | Returns a promise that resolves with the current access token. |
The token will be refreshed if expires within minValidity seconds. The minValidity parameter is optional and defaults to 10. If -1 is passed as minValidity, the token will be forcibly refreshed.
A typical usage for this function is to be called before every API call, using a request interceptor in your HTTP client library.
import axios from 'axios'
import { getToken } from '@josempgon/vue-keycloak'
// Create an instance of axios with the base URL read from the environment
const baseURL = import.meta.env.VITE_API_URL
const instance = axios.create({ baseURL })
// Request interceptor for API calls
instance.interceptors.request.use(
async config => {
const token = await getToken()
config.headers['Authorization'] = `Bearer ${token}`
return config
},
error => {
Promise.reject(error)
},
)
Always call getToken() when you need a token to send. The token value exposed by useKeycloak() is a snapshot from the last time the token was set — it is not refreshed in the background, so it will eventually expire in place and be rejected by your API. getToken() refreshes it when needed and updates the reactive state.
Composition API
<script setup>
import { useKeycloak } from '@josempgon/vue-keycloak';
const { isPending, isAuthenticated, error, username, userId, keycloak } = useKeycloak();
</script>
<template>
<div v-if="isPending">
<h2>Loading...</h2>
</div>
<div v-if="isAuthenticated">
<h1>Welcome to Your Keycloak Secured Vue.js App</h1>
<h2>User: {{ username }}</h2>
<h2>User ID: {{ userId }}</h2>
<div>
<button @click="keycloak.logout">Logout</button>
</div>
</div>
<div v-if="error">
<h2>Authentication Error</h2>
<h3>{{ error }}</h3>
</div>
</template>
<style>
#app {
text-align: center;
}
button {
cursor: pointer;
}
</style>
useKeycloak
The useKeycloak function exposes the following data.
Reactive State
| State | Type | Description |
|---|---|---|
| keycloak | ShallowRef<Keycloak> |
Instance of the keycloak-js adapter. |
| isAuthenticated | Ref<boolean> |
If true the user is authenticated. |
| isPending | Ref<boolean> |
If true the authentication request is still pending. |
| hasFailed | Ref<boolean> |
If true an error occurred on initialization or Keycloak request. |
| error | Ref<Error | null> |
Info on error that occurred (null if no error) |
| token | Ref<string> |
Raw value of the access token. May be expired. |
| decodedToken | Ref<KeycloakTokenParsed> |
Decoded value of the access token. |
| username | Ref<string> |
Username. Extracted from decodedToken['preferred_username']. |
| userId | Ref<string> |
User identifier. Extracted from decodedToken['sub']. |
| roles | Ref<string[]> |
List of the user's roles. |
| resourceRoles | Ref<Record<string, string[]>> |
List of the user's roles in specific resources. |
Functions
| Function | Type | Description |
|---|---|---|
| hasRoles | (roles: string[]) => boolean | Returns true if the user has all the given roles. |
| hasResourceRoles | (roles: string[], resource: string) => boolean | Returns true if the user has all the given roles in a resource. |
License
This project is licensed under the Apache License 2.0.
Originally developed by Gery Hirschfeld (2021).
Maintained and extended by José Miguel Gonçalves (2021-present).
Related Packages
Version History
| Version | Released | License |
|---|---|---|
| 3.3.11 | Apache-2.0 | |
| 3.3.10 | Apache-2.0 | |
| 3.3.9 | Apache-2.0 | |
| 3.3.8 | Apache-2.0 | |
| 3.3.7 | Apache-2.0 | |
| 3.3.6 | Apache-2.0 | |
| 3.3.5 | Apache-2.0 | |
| 3.3.4 | Apache-2.0 | |
| 3.3.3 | Apache-2.0 | |
| 3.3.2 | Apache-2.0 | |
| 3.3.1 | Apache-2.0 | |
| 3.3.0 | Apache-2.0 | |
| 3.2.1 | Apache-2.0 | |
| 3.2.0 | Apache-2.0 | |
| 3.1.1 | Apache-2.0 | |
| 3.1.0 | Apache-2.0 | |
| 3.0.1 | Apache-2.0 | |
| 3.0.0 | Apache-2.0 | |
| 2.7.1 | Apache-2.0 | |
| 2.7.0 | Apache-2.0 | |
| 2.6.0 | Apache-2.0 | |
| 2.5.0 | Apache-2.0 | |
| 2.4.0 | Apache-2.0 | |
| 2.3.3 | Apache-2.0 | |
| 2.3.2 | Apache-2.0 | |
| 2.3.1 | Apache-2.0 | |
| 2.3.0 | Apache-2.0 | |
| 2.2.0 | Apache-2.0 | |
| 2.1.0 | Apache-2.0 | |
| 2.0.1 | Apache-2.0 |
Showing the latest 30 of 41. See every release on npm