{"id":32459494,"url":"https://github.com/productdevbook/nuxt-keycloak","last_synced_at":"2026-05-15T11:37:13.156Z","repository":{"id":320093029,"uuid":"1080781606","full_name":"productdevbook/nuxt-keycloak","owner":"productdevbook","description":"Comprehensive Keycloak authentication module for Nuxt 4 with SSR support, auto token refresh, role-based guards, and TypeScript.","archived":false,"fork":false,"pushed_at":"2025-10-22T18:00:54.000Z","size":141,"stargazers_count":10,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-11-01T19:15:25.567Z","etag":null,"topics":["keycloak","keycloak-client","keycloak-js","nuxt"],"latest_commit_sha":null,"homepage":"https://keycloak.org","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/productdevbook.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":["productdevbook"]}},"created_at":"2025-10-21T21:25:53.000Z","updated_at":"2025-10-29T11:05:45.000Z","dependencies_parsed_at":"2025-10-21T23:28:26.290Z","dependency_job_id":"eae6e716-e597-4ee5-8a9d-0b009c53057a","html_url":"https://github.com/productdevbook/nuxt-keycloak","commit_stats":null,"previous_names":["productdevbook/nuxt-keycloak"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/productdevbook/nuxt-keycloak","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/productdevbook%2Fnuxt-keycloak","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/productdevbook%2Fnuxt-keycloak/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/productdevbook%2Fnuxt-keycloak/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/productdevbook%2Fnuxt-keycloak/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/productdevbook","download_url":"https://codeload.github.com/productdevbook/nuxt-keycloak/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/productdevbook%2Fnuxt-keycloak/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33065719,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-15T11:35:32.926Z","status":"ssl_error","status_checked_at":"2026-05-15T11:35:31.362Z","response_time":103,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["keycloak","keycloak-client","keycloak-js","nuxt"],"created_at":"2025-10-26T11:01:20.320Z","updated_at":"2026-05-15T11:37:13.144Z","avatar_url":"https://github.com/productdevbook.png","language":"TypeScript","funding_links":["https://github.com/sponsors/productdevbook"],"categories":["TypeScript"],"sub_categories":[],"readme":"# Nuxt Keycloak\n\n[![npm version][npm-version-src]][npm-version-href]\n[![npm downloads][npm-downloads-src]][npm-downloads-href]\n[![License][license-src]][license-href]\n[![Nuxt][nuxt-src]][nuxt-href]\n\nComprehensive Keycloak authentication module for Nuxt 4 with SSR support, auto token refresh, role-based guards, and TypeScript.\n\n- [✨ \u0026nbsp;Release Notes](/CHANGELOG.md)\n\n## Features\n\n- 🔐 **Hybrid Authentication** - Support for both client-side (SPA) and server-side rendering (SSR) modes\n- 🔄 **Auto Token Refresh** - Automatically refresh access tokens before expiration\n- 🛡️ **Role-Based Guards** - Protect routes with realm and client/resource roles\n- 📘 **TypeScript Support** - Full type safety with comprehensive TypeScript definitions\n- 🔍 **Silent Check-SSO** - Non-intrusive authentication check for optional auth (auto-generated HTML file)\n- 🔑 **JWT Verification** - Secure server-side token validation using JWKS with `jose`\n- ⚙️ **Configurable** - Every feature can be toggled via configuration\n- 🎯 **Production Ready** - Error handling, logging, and security best practices\n- 🚀 **Zero Config** - Silent Check-SSO HTML automatically generated in public directory\n\n## Quick Setup\n\n1. Install the module:\n\n```bash\npnpm add nuxt-keycloak\n# or\nnpm install nuxt-keycloak\n# or\nyarn add nuxt-keycloak\n```\n\n2. Add `nuxt-keycloak` to the `modules` section of `nuxt.config.ts`:\n\n```typescript\nexport default defineNuxtConfig({\n  modules: ['nuxt-keycloak'],\n\n  keycloak: {\n    url: 'http://localhost:8080',\n    realm: 'your-realm',\n    clientId: 'your-client-id',\n  }\n})\n```\n\n3. Configure environment variables (optional):\n\n```env\nNUXT_PUBLIC_KEYCLOAK_URL=http://localhost:8080\nNUXT_PUBLIC_KEYCLOAK_REALM=your-realm\nNUXT_PUBLIC_KEYCLOAK_CLIENT_ID=your-client-id\n```\n\nThat's it! You can now use Keycloak authentication in your Nuxt app ✨\n\n\n## Usage\n\n### Basic Authentication\n\nUse the `useKeycloak()` composable in your components:\n\n```vue\n\u003cscript setup\u003e\nconst { isAuthenticated, user, login, logout } = useKeycloak()\n\u003c/script\u003e\n\n\u003ctemplate\u003e\n  \u003cdiv\u003e\n    \u003cdiv v-if=\"!isAuthenticated\"\u003e\n      \u003cbutton @click=\"login()\"\u003eLogin\u003c/button\u003e\n    \u003c/div\u003e\n    \u003cdiv v-else\u003e\n      \u003cp\u003eWelcome, {{ user?.username }}!\u003c/p\u003e\n      \u003cbutton @click=\"logout()\"\u003eLogout\u003c/button\u003e\n    \u003c/div\u003e\n  \u003c/div\u003e\n\u003c/template\u003e\n```\n\n### Protecting Pages\n\nProtect entire pages by adding middleware:\n\n```vue\n\u003c!-- pages/dashboard.vue --\u003e\n\u003cscript setup\u003e\ndefinePageMeta({\n  middleware: 'keycloak-auth'\n})\n\u003c/script\u003e\n```\n\n### Role-Based Access Control\n\nProtect pages based on Keycloak roles:\n\n```vue\n\u003c!-- pages/admin.vue --\u003e\n\u003cscript setup\u003e\ndefinePageMeta({\n  middleware: ['keycloak-auth', 'keycloak-role'],\n  keycloakRoles: {\n    realm: ['admin'], // Requires 'admin' realm role\n    resource: {  // OR requires client role\n      clientId: 'my-app',\n      roles: ['manager']\n    }\n  }\n})\n\u003c/script\u003e\n```\n\n### Protecting API Routes\n\nServer utilities are automatically available in Nuxt server routes (no import needed):\n\n```typescript\n// server/api/protected.ts\nexport default defineEventHandler(async (event) =\u003e {\n  // Require authentication - auto-imported\n  const user = requireKeycloakAuth(event)\n\n  return {\n    message: 'Protected data',\n    user\n  }\n})\n```\n\n```typescript\n// server/api/admin.ts\nexport default defineEventHandler(async (event) =\u003e {\n  // Require specific role - auto-imported\n  const user = requireRealmRole(event, 'admin')\n\n  return {\n    message: 'Admin data',\n    user\n  }\n})\n```\n\nYou can also explicitly import from `nuxt-keycloak/server`:\n\n```typescript\n// server/api/custom.ts\nimport { extractToken, verifyKeycloakToken, requireRealmRole } from 'nuxt-keycloak/server'\n\nexport default defineEventHandler(async (event) =\u003e {\n  const token = extractToken(event)\n  const user = await verifyKeycloakToken(token)\n\n  // Use imported functions\n  requireRealmRole(event, 'admin')\n\n  return { user }\n})\n```\n\n### Using with Traefik or Reverse Proxy\n\nWhen 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:\n\n```typescript\nexport default defineNuxtConfig({\n  keycloak: {\n    url: process.env.NUXT_PUBLIC_KEYCLOAK_URL,\n    realm: process.env.NUXT_PUBLIC_KEYCLOAK_REALM,\n    clientId: process.env.NUXT_PUBLIC_KEYCLOAK_CLIENT_ID,\n    server: {\n      verifyToken: 'decode', // Decode only, trust proxy verification\n      middleware: true,\n    },\n  }\n})\n```\n\nOr use environment variable:\n```env\nNUXT_KEYCLOAK_SERVER_VERIFY_TOKEN=decode\n```\n\n**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.\n\n### Manual Token Verification\n\nFor more control, manually verify tokens:\n\n```typescript\n// server/api/custom.ts\nexport default defineEventHandler(async (event) =\u003e {\n  const token = extractToken(event)\n\n  if (!token) {\n    throw createError({\n      statusCode: 401,\n      message: 'No token provided'\n    })\n  }\n\n  const user = await verifyKeycloakToken(token)\n\n  if (!user) {\n    throw createError({\n      statusCode: 401,\n      message: 'Invalid token'\n    })\n  }\n\n  // Check custom logic\n  if (!hasRealmRole(event, 'special-access')) {\n    throw createError({\n      statusCode: 403,\n      message: 'Forbidden'\n    })\n  }\n\n  return { user }\n})\n```\n\n## Configuration\n\n### Module Options\n\nAll configuration options:\n\n```typescript\nexport default defineNuxtConfig({\n  keycloak: {\n    // Keycloak server URL\n    url: 'http://localhost:8080',\n\n    // Realm name\n    realm: 'my-realm',\n\n    // Client ID (must be a public client)\n    clientId: 'my-client',\n\n    // Keycloak initialization options\n    initOptions: {\n      onLoad: 'check-sso', // or 'login-required'\n      pkceMethod: 'S256',\n      flow: 'standard',\n      checkLoginIframe: false,\n      silentCheckSsoRedirectUri: 'http://localhost:3000/silent-check-sso.html'\n    },\n\n    // Server-side configuration\n    server: {\n      verifyToken: true, // true = full JWKS verification, false = disabled, 'decode' = decode only (for reverse proxy scenarios)\n      middleware: false, // Enable global middleware\n      jwksCacheDuration: 600000, // JWKS cache duration (10 minutes)\n      rejectUnauthorized: true // Verify SSL certificates for JWKS endpoint\n    },\n\n    // Client-side configuration\n    client: {\n      autoRefreshToken: true, // Auto-refresh tokens\n      minTokenValidity: 30, // Refresh when \u003c 30s validity\n      persistRefreshToken: true // Store refresh token in localStorage\n    }\n  }\n})\n```\n\n### Environment Variables\n\nUse environment variables for different environments:\n\n```env\n# Public (exposed to client)\nNUXT_PUBLIC_KEYCLOAK_URL=https://keycloak.example.com\nNUXT_PUBLIC_KEYCLOAK_REALM=production\nNUXT_PUBLIC_KEYCLOAK_CLIENT_ID=nuxt-app\nNUXT_PUBLIC_APP_URL=https://app.example.com\n\n# Private (server-only)\nNUXT_KEYCLOAK_SERVER_VERIFY_TOKEN=true  # true, false, or 'decode'\nNUXT_KEYCLOAK_SERVER_MIDDLEWARE=false\n```\n\n## API Reference\n\n### Composables\n\n#### `useKeycloak()`\n\nReturns:\n- `keycloak` - Keycloak instance (client-side only)\n- `isAuthenticated` - Authentication status\n- `isInitialized` - Initialization status\n- `user` - User profile data\n- `token` - Access token\n- `tokenParsed` - Parsed token claims\n- `login(redirectUri?)` - Redirect to login\n- `logout(redirectUri?)` - Logout user\n- `register(redirectUri?)` - Redirect to registration\n- `updateToken(minValidity?)` - Manually refresh token\n- `loadUserProfile()` - Load user profile\n- `hasRealmRole(role)` - Check realm role\n- `hasResourceRole(role, resource?)` - Check client role\n- `isTokenExpired(minValidity?)` - Check token expiration\n\n### Server Utilities\n\nAll utilities are **auto-imported** in Nuxt server routes. You can also explicitly import them from `nuxt-keycloak/server`:\n\n```typescript\nimport {\n  verifyKeycloakToken,\n  extractToken,\n  requireKeycloakAuth\n} from 'nuxt-keycloak/server'\n```\n\n**Available Functions:**\n\n- `verifyKeycloakToken(token)` - Verify JWT token using JWKS\n- `extractToken(event)` - Extract Bearer token from Authorization header\n- `getKeycloakUser(event)` - Get authenticated user from context\n- `getKeycloakToken(event)` - Get access token from context\n- `isAuthenticated(event)` - Check if user is authenticated\n- `hasRealmRole(event, role)` - Check if user has realm role\n- `hasResourceRole(event, role, resource?)` - Check if user has client role\n- `requireKeycloakAuth(event)` - Require authentication (throws 401 if not authenticated)\n- `requireRealmRole(event, role)` - Require realm role (throws 403 if missing)\n- `requireResourceRole(event, role, resource?)` - Require client role (throws 403 if missing)\n\n### Middleware\n\n- `keycloak-auth` - Protect routes (requires authentication)\n- `keycloak-role` - Enforce role-based access (use with route meta)\n\n## Keycloak Setup\n\n### 1. Create a Realm\n\n1. Login to Keycloak Admin Console\n2. Create a new realm or use existing\n3. Note the realm name\n\n### 2. Create a Client\n\n1. Go to Clients → Create\n2. **Client ID**: Your app name (e.g., `nuxt-app`)\n3. **Client Protocol**: `openid-connect`\n4. **Access Type**: `public` (for SPA/Nuxt)\n5. **Valid Redirect URIs**: `http://localhost:3000/*` (or your app URL)\n6. **Web Origins**: `http://localhost:3000` (or your app URL)\n7. Save\n\n### 3. Configure Client Settings\n\n- **Standard Flow**: Enabled\n- **Direct Access Grants**: Enabled (for password grant)\n- **Implicit Flow**: Disabled (use PKCE instead)\n\n### 4. Create Roles (Optional)\n\n1. Go to Roles → Add Role\n2. Create roles like `admin`, `user`, `manager`\n3. Assign roles to users\n\n### 5. Create Users\n\n1. Go to Users → Add User\n2. Set username, email, etc.\n3. Go to Credentials tab → Set password\n4. Go to Role Mappings → Assign roles\n\n## Examples\n\nCheck out the [playground](./playground) directory for comprehensive examples:\n\n- **Public Page** - `/` - No authentication required\n- **Dashboard** - `/dashboard` - Requires authentication\n- **Admin Panel** - `/admin` - Requires 'admin' realm role\n- **Profile** - `/profile` - Shows user info and token details\n\n## Troubleshooting\n\n### CORS Errors\n\nMake sure your Keycloak client has the correct **Web Origins** configured. Add your app's origin (e.g., `http://localhost:3000`).\n\n### Token Not Refreshing\n\nCheck that:\n1. `client.autoRefreshToken` is `true` in config\n2. Refresh token is valid and not expired\n3. Client has **Standard Flow** enabled in Keycloak\n\n### Silent Check-SSO Not Working\n\nThe module automatically creates `/public/silent-check-sso.html` for you. If you need to customize it:\n\n1. The file is automatically generated in your `public/` directory\n2. Configure `initOptions.silentCheckSsoRedirectUri` in config (e.g., `http://localhost:3000/silent-check-sso.html`)\n3. Add the URL to **Valid Redirect URIs** in Keycloak client\n\nNote: The file is auto-generated by the module on `nuxt prepare`/`nuxt dev`, so you don't need to manually create it.\n\n### Role Middleware Not Working\n\nEnsure:\n1. User has the required role assigned in Keycloak\n2. Route meta includes `keycloakRoles` configuration\n3. Both `keycloak-auth` and `keycloak-role` middlewares are applied\n\n## Contribution\n\n\u003cdetails\u003e\n  \u003csummary\u003eLocal development\u003c/summary\u003e\n\n  ```bash\n  # Install dependencies\n  pnpm install\n\n  # Generate type stubs\n  pnpm run dev:prepare\n\n  # Develop with the playground\n  pnpm run dev\n\n  # Build the playground\n  pnpm run dev:build\n\n  # Run ESLint\n  pnpm run lint\n\n  # Run Vitest\n  pnpm run test\n  pnpm run test:watch\n\n  # Release new version\n  pnpm run release\n  ```\n\n\u003c/details\u003e\n\n## Credits\n\nThis project was inspired by and builds upon ideas from:\n- [vue-keycloak](https://github.com/JoseGoncalves/vue-keycloak) by José Miguel Gonçalves and Gery Hirschfeld (Apache 2.0)\n\nSpecial thanks to the open-source community for their contributions to Keycloak integration solutions.\n\n## License\n\n[MIT License](./LICENSE)\n\nCopyright (c) 2025\n\n\u003c!-- Badges --\u003e\n[npm-version-src]: https://img.shields.io/npm/v/nuxt-keycloak/latest.svg?style=flat\u0026colorA=020420\u0026colorB=00DC82\n[npm-version-href]: https://npmjs.com/package/nuxt-keycloak\n\n[npm-downloads-src]: https://img.shields.io/npm/dm/nuxt-keycloak.svg?style=flat\u0026colorA=020420\u0026colorB=00DC82\n[npm-downloads-href]: https://npm.chart.dev/nuxt-keycloak\n\n[license-src]: https://img.shields.io/npm/l/nuxt-keycloak.svg?style=flat\u0026colorA=020420\u0026colorB=00DC82\n[license-href]: https://npmjs.com/package/nuxt-keycloak\n\n[nuxt-src]: https://img.shields.io/badge/Nuxt-020420?logo=nuxt.js\n[nuxt-href]: https://nuxt.com\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fproductdevbook%2Fnuxt-keycloak","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fproductdevbook%2Fnuxt-keycloak","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fproductdevbook%2Fnuxt-keycloak/lists"}