nuxt-keycloak
| Install | |
|---|---|
npm install nuxt-keycloak |
|
| Latest Version: | 0.2.1 |
| Vue: | 3 |
| License: | MIT |
| Last Updated: | Oct 22, 2025 |
| Links: | GitHub · npm |
Nuxt Keycloak
Comprehensive Keycloak authentication module for Nuxt 4 with SSR support, auto token refresh, role-based guards, and TypeScript.
Features
- 🔐 Hybrid Authentication - Support for both client-side (SPA) and server-side rendering (SSR) modes
- 🔄 Auto Token Refresh - Automatically refresh access tokens before expiration
- 🛡️ Role-Based Guards - Protect routes with realm and client/resource roles
- 📘 TypeScript Support - Full type safety with comprehensive TypeScript definitions
- 🔍 Silent Check-SSO - Non-intrusive authentication check for optional auth (auto-generated HTML file)
- 🔑 JWT Verification - Secure server-side token validation using JWKS with
jose - ⚙️ Configurable - Every feature can be toggled via configuration
- 🎯 Production Ready - Error handling, logging, and security best practices
- 🚀 Zero Config - Silent Check-SSO HTML automatically generated in public directory
Quick Setup
- Install the module:
pnpm add nuxt-keycloak
# or
npm install nuxt-keycloak
# or
yarn add nuxt-keycloak
- Add
nuxt-keycloakto themodulessection ofnuxt.config.ts:
export default defineNuxtConfig({
modules: ['nuxt-keycloak'],
keycloak: {
url: 'http://localhost:8080',
realm: 'your-realm',
clientId: 'your-client-id',
}
})
- Configure environment variables (optional):
NUXT_PUBLIC_KEYCLOAK_URL=http://localhost:8080
NUXT_PUBLIC_KEYCLOAK_REALM=your-realm
NUXT_PUBLIC_KEYCLOAK_CLIENT_ID=your-client-id
That's it! You can now use Keycloak authentication in your Nuxt app ✨
Usage
Basic Authentication
Use the useKeycloak() composable in your components:
<script setup>
const { isAuthenticated, user, login, logout } = useKeycloak()
</script>
<template>
<div>
<div v-if="!isAuthenticated">
<button @click="login()">Login</button>
</div>
<div v-else>
<p>Welcome, {{ user?.username }}!</p>
<button @click="logout()">Logout</button>
</div>
</div>
</template>
Protecting Pages
Protect entire pages by adding middleware:
<!-- pages/dashboard.vue -->
<script setup>
definePageMeta({
middleware: 'keycloak-auth'
})
</script>
Role-Based Access Control
Protect pages based on Keycloak roles:
<!-- pages/admin.vue -->
<script setup>
definePageMeta({
middleware: ['keycloak-auth', 'keycloak-role'],
keycloakRoles: {
realm: ['admin'], // Requires 'admin' realm role
resource: { // OR requires client role
clientId: 'my-app',
roles: ['manager']
}
}
})
</script>
Protecting API Routes
Server utilities are automatically available in Nuxt server routes (no import needed):
// server/api/protected.ts
export default defineEventHandler(async (event) => {
// Require authentication - auto-imported
const user = requireKeycloakAuth(event)
return {
message: 'Protected data',
user
}
})
// server/api/admin.ts
export default defineEventHandler(async (event) => {
// Require specific role - auto-imported
const user = requireRealmRole(event, 'admin')
return {
message: 'Admin data',
user
}
})
You can also explicitly import from nuxt-keycloak/server:
// server/api/custom.ts
import { extractToken, verifyKeycloakToken, requireRealmRole } from 'nuxt-keycloak/server'
export default defineEventHandler(async (event) => {
const token = extractToken(event)
const user = await verifyKeycloakToken(token)
// Use imported functions
requireRealmRole(event, 'admin')
return { user }
})
Using with Traefik or Reverse Proxy
When deploying behind Traefik or another reverse proxy that already verifies JWT tokens, you can configure the module to skip JWKS verification and simply decode tokens:
export default defineNuxtConfig({
keycloak: {
url: process.env.NUXT_PUBLIC_KEYCLOAK_URL,
realm: process.env.NUXT_PUBLIC_KEYCLOAK_REALM,
clientId: process.env.NUXT_PUBLIC_KEYCLOAK_CLIENT_ID,
server: {
verifyToken: 'decode', // Decode only, trust proxy verification
middleware: true,
},
}
})
Or use environment variable:
NUXT_KEYCLOAK_SERVER_VERIFY_TOKEN=decode
Important: Only use verifyToken: 'decode' when tokens are pre-verified by a trusted reverse proxy (Traefik ForwardAuth, etc.). This mode skips all signature and expiration validation.
Manual Token Verification
For more control, manually verify tokens:
// server/api/custom.ts
export default defineEventHandler(async (event) => {
const token = extractToken(event)
if (!token) {
throw createError({
statusCode: 401,
message: 'No token provided'
})
}
const user = await verifyKeycloakToken(token)
if (!user) {
throw createError({
statusCode: 401,
message: 'Invalid token'
})
}
// Check custom logic
if (!hasRealmRole(event, 'special-access')) {
throw createError({
statusCode: 403,
message: 'Forbidden'
})
}
return { user }
})
Configuration
Module Options
All configuration options:
export default defineNuxtConfig({
keycloak: {
// Keycloak server URL
url: 'http://localhost:8080',
// Realm name
realm: 'my-realm',
// Client ID (must be a public client)
clientId: 'my-client',
// Keycloak initialization options
initOptions: {
onLoad: 'check-sso', // or 'login-required'
pkceMethod: 'S256',
flow: 'standard',
checkLoginIframe: false,
silentCheckSsoRedirectUri: 'http://localhost:3000/silent-check-sso.html'
},
// Server-side configuration
server: {
verifyToken: true, // true = full JWKS verification, false = disabled, 'decode' = decode only (for reverse proxy scenarios)
middleware: false, // Enable global middleware
jwksCacheDuration: 600000, // JWKS cache duration (10 minutes)
rejectUnauthorized: true // Verify SSL certificates for JWKS endpoint
},
// Client-side configuration
client: {
autoRefreshToken: true, // Auto-refresh tokens
minTokenValidity: 30, // Refresh when < 30s validity
persistRefreshToken: true // Store refresh token in localStorage
}
}
})
Environment Variables
Use environment variables for different environments:
# Public (exposed to client)
NUXT_PUBLIC_KEYCLOAK_URL=https://keycloak.example.com
NUXT_PUBLIC_KEYCLOAK_REALM=production
NUXT_PUBLIC_KEYCLOAK_CLIENT_ID=nuxt-app
NUXT_PUBLIC_APP_URL=https://app.example.com
# Private (server-only)
NUXT_KEYCLOAK_SERVER_VERIFY_TOKEN=true # true, false, or 'decode'
NUXT_KEYCLOAK_SERVER_MIDDLEWARE=false
API Reference
Composables
useKeycloak()
Returns:
keycloak- Keycloak instance (client-side only)isAuthenticated- Authentication statusisInitialized- Initialization statususer- User profile datatoken- Access tokentokenParsed- Parsed token claimslogin(redirectUri?)- Redirect to loginlogout(redirectUri?)- Logout userregister(redirectUri?)- Redirect to registrationupdateToken(minValidity?)- Manually refresh tokenloadUserProfile()- Load user profilehasRealmRole(role)- Check realm rolehasResourceRole(role, resource?)- Check client roleisTokenExpired(minValidity?)- Check token expiration
Server Utilities
All utilities are auto-imported in Nuxt server routes. You can also explicitly import them from nuxt-keycloak/server:
import {
verifyKeycloakToken,
extractToken,
requireKeycloakAuth
} from 'nuxt-keycloak/server'
Available Functions:
verifyKeycloakToken(token)- Verify JWT token using JWKSextractToken(event)- Extract Bearer token from Authorization headergetKeycloakUser(event)- Get authenticated user from contextgetKeycloakToken(event)- Get access token from contextisAuthenticated(event)- Check if user is authenticatedhasRealmRole(event, role)- Check if user has realm rolehasResourceRole(event, role, resource?)- Check if user has client rolerequireKeycloakAuth(event)- Require authentication (throws 401 if not authenticated)requireRealmRole(event, role)- Require realm role (throws 403 if missing)requireResourceRole(event, role, resource?)- Require client role (throws 403 if missing)
Middleware
keycloak-auth- Protect routes (requires authentication)keycloak-role- Enforce role-based access (use with route meta)
Keycloak Setup
1. Create a Realm
- Login to Keycloak Admin Console
- Create a new realm or use existing
- Note the realm name
2. Create a Client
- Go to Clients → Create
- Client ID: Your app name (e.g.,
nuxt-app) - Client Protocol:
openid-connect - Access Type:
public(for SPA/Nuxt) - Valid Redirect URIs:
http://localhost:3000/*(or your app URL) - Web Origins:
http://localhost:3000(or your app URL) - Save
3. Configure Client Settings
- Standard Flow: Enabled
- Direct Access Grants: Enabled (for password grant)
- Implicit Flow: Disabled (use PKCE instead)
4. Create Roles (Optional)
- Go to Roles → Add Role
- Create roles like
admin,user,manager - Assign roles to users
5. Create Users
- Go to Users → Add User
- Set username, email, etc.
- Go to Credentials tab → Set password
- Go to Role Mappings → Assign roles
Examples
Check out the playground directory for comprehensive examples:
- Public Page -
/- No authentication required - Dashboard -
/dashboard- Requires authentication - Admin Panel -
/admin- Requires 'admin' realm role - Profile -
/profile- Shows user info and token details
Troubleshooting
CORS Errors
Make sure your Keycloak client has the correct Web Origins configured. Add your app's origin (e.g., http://localhost:3000).
Token Not Refreshing
Check that:
client.autoRefreshTokenistruein config- Refresh token is valid and not expired
- Client has Standard Flow enabled in Keycloak
Silent Check-SSO Not Working
The module automatically creates /public/silent-check-sso.html for you. If you need to customize it:
- The file is automatically generated in your
public/directory - Configure
initOptions.silentCheckSsoRedirectUriin config (e.g.,http://localhost:3000/silent-check-sso.html) - Add the URL to Valid Redirect URIs in Keycloak client
Note: The file is auto-generated by the module on nuxt prepare/nuxt dev, so you don't need to manually create it.
Role Middleware Not Working
Ensure:
- User has the required role assigned in Keycloak
- Route meta includes
keycloakRolesconfiguration - Both
keycloak-authandkeycloak-rolemiddlewares are applied
Contribution
Local development
# Install dependencies
pnpm install
# Generate type stubs
pnpm run dev:prepare
# Develop with the playground
pnpm run dev
# Build the playground
pnpm run dev:build
# Run ESLint
pnpm run lint
# Run Vitest
pnpm run test
pnpm run test:watch
# Release new version
pnpm run release
Credits
This project was inspired by and builds upon ideas from:
- vue-keycloak by José Miguel Gonçalves and Gery Hirschfeld (Apache 2.0)
Special thanks to the open-source community for their contributions to Keycloak integration solutions.
License
Copyright (c) 2025
Version History
| Version | Released | Vue | License |
|---|---|---|---|
| 0.2.1 | ^3.0 | MIT | |
| 0.2.0 | ^3.0 | MIT | |
| 0.1.0 | ^3.0 | MIT | |
| 0.0.2 | ^3.0 | MIT | |
| 0.0.1 | ^3.0 | MIT |