{"_id":"@azerothian/keycloak-api","name":"@azerothian/keycloak-api","dist-tags":{"latest":"0.0.1"},"versions":{"0.0.1":{"name":"@azerothian/keycloak-api","version":"0.0.1","private":false,"description":"NestJS module for Keycloak authentication and administration","license":"MIT","author":{"name":"Azerothian"},"repository":{"type":"git","url":"git+https://github.com/Azerothian/keycloak-api.git"},"homepage":"https://github.com/Azerothian/keycloak-api#readme","main":"./dist/cjs/index.js","module":"./dist/esm/index.js","types":"./dist/cjs/index.d.ts","exports":{".":{"import":{"types":"./dist/esm/index.d.ts","default":"./dist/esm/index.js"},"require":{"types":"./dist/cjs/index.d.ts","default":"./dist/cjs/index.js"}},"./admin":{"import":{"types":"./dist/esm/admin/index.d.ts","default":"./dist/esm/admin/index.js"},"require":{"types":"./dist/cjs/admin/index.d.ts","default":"./dist/cjs/admin/index.js"}},"./auth":{"import":{"types":"./dist/esm/auth/index.d.ts","default":"./dist/esm/auth/index.js"},"require":{"types":"./dist/cjs/auth/index.d.ts","default":"./dist/cjs/auth/index.js"}},"./decorators":{"import":{"types":"./dist/esm/decorators/index.d.ts","default":"./dist/esm/decorators/index.js"},"require":{"types":"./dist/cjs/decorators/index.d.ts","default":"./dist/cjs/decorators/index.js"}},"./types":{"import":{"types":"./dist/esm/types/index.d.ts","default":"./dist/esm/types/index.js"},"require":{"types":"./dist/cjs/types/index.d.ts","default":"./dist/cjs/types/index.js"}},"./testing":{"import":{"types":"./dist/esm/testing/index.d.ts","default":"./dist/esm/testing/index.js"},"require":{"types":"./dist/cjs/testing/index.d.ts","default":"./dist/cjs/testing/index.js"}}},"typesVersions":{"*":{"admin":["./dist/cjs/admin/index.d.ts"],"auth":["./dist/cjs/auth/index.d.ts"],"decorators":["./dist/cjs/decorators/index.d.ts"],"types":["./dist/cjs/types/index.d.ts"],"testing":["./dist/cjs/testing/index.d.ts"]}},"scripts":{"build":"pnpm clean && tsc -p tsconfig.cjs.json && tsc -p tsconfig.esm.json","postbuild":"echo '{\"type\":\"module\"}' > dist/esm/package.json","dev":"tsc -p tsconfig.cjs.json --watch","clean":"rm -rf dist","type-check":"tsc --noEmit","test":"vitest run","test:watch":"vitest","prepublishOnly":"pnpm clean && pnpm build"},"dependencies":{"@keycloak/keycloak-admin-client":"^26.5.2","jwks-rsa":"^3.1.0","passport-jwt":"^4.0.1","reflect-metadata":"^0.2.1"},"devDependencies":{"@nestjs/common":"^10.3.0","@nestjs/config":"^3.1.1","@nestjs/core":"^10.3.0","@nestjs/jwt":"^10.2.0","@nestjs/passport":"^10.0.3","@nestjs/testing":"^10.3.0","@types/passport-jwt":"^4.0.1","@types/node":"^20.11.0","rxjs":"^7.8.1","typescript":"^5.3.3","vitest":"^1.2.0"},"peerDependencies":{"@nestjs/common":"^10.0.0","@nestjs/config":"^3.0.0","@nestjs/core":"^10.0.0","@nestjs/passport":"^10.0.0","rxjs":"^7.0.0"},"gitHead":"d3e32f1553114a7ac03dca2926f4b0f06a79850e","_id":"@azerothian/keycloak-api@0.0.1","bugs":{"url":"https://github.com/Azerothian/keycloak-api/issues"},"_nodeVersion":"24.12.0","_npmVersion":"11.6.2","dist":{"integrity":"sha512-w/T7sLzmyGmCMBcPWAHxp4OkW6ogtg4UiPfZ3FTYWcRH0rwpaiFaHkKn7XWvXTnFZtJBZJd4QDQWUBoBiMbPTA==","shasum":"179c11f1a7b3b9d0e2e7b6e6807ab76bb315ea30","tarball":"https://registry.npmjs.org/@azerothian/keycloak-api/-/keycloak-api-0.0.1.tgz","fileCount":148,"unpackedSize":354481,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQDRY4ZPOrWlYlPUGuWrJOI6MkWC5q8ora78rdZ/NctcOAIhAKjgGNER58lqXSRGwPUX8Pzii9BazmS6ID7+WmIucr/J"}]},"_npmUser":{"name":"matthew.m.mckenzie","email":"matthew.m.mckenzie@gmail.com"},"directories":{},"maintainers":[{"name":"matthew.m.mckenzie","email":"matthew.m.mckenzie@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/keycloak-api_0.0.1_1771657396739_0.45858473451182724"},"_hasShrinkwrap":false}},"time":{"created":"2026-02-21T07:03:16.632Z","0.0.1":"2026-02-21T07:03:16.945Z","modified":"2026-02-21T07:03:17.213Z"},"maintainers":[{"name":"matthew.m.mckenzie","email":"matthew.m.mckenzie@gmail.com"}],"description":"NestJS module for Keycloak authentication and administration","homepage":"https://github.com/Azerothian/keycloak-api#readme","repository":{"type":"git","url":"git+https://github.com/Azerothian/keycloak-api.git"},"author":{"name":"Azerothian"},"bugs":{"url":"https://github.com/Azerothian/keycloak-api/issues"},"license":"MIT","readme":"# @azerothian/keycloak-api\n\nNestJS module for Keycloak authentication and administration. Provides multi-realm JWT authentication, 100+ admin REST API methods, route protection decorators, JWKS key caching, and comprehensive testing utilities.\n\n## Features\n\n- **Multi-Realm JWT Authentication** - Validate JWT tokens from any realm on a Keycloak instance with automatic JWKS key resolution and caching\n- **Comprehensive Admin API** - 100+ methods for realm, user, group, role, session, and event management\n- **Route Protection Decorators** - `@Public()`, `@CurrentUser()`, and `@Permissions()` for fine-grained access control\n- **JWKS Caching** - Automatic signing key caching with configurable refresh intervals to minimize Keycloak calls\n- **Testing Utilities** - Mock JWT tokens and strategies for integration testing without a running Keycloak instance\n\n## Installation\n\n```bash\nnpm install @azerothian/keycloak-api\n```\n\n### Peer Dependencies\n\n```bash\nnpm install @nestjs/common @nestjs/core @nestjs/config @nestjs/passport rxjs\n```\n\n## Quick Start\n\n### 1. Authentication Setup\n\nImport the auth module and configure your Keycloak instance:\n\n```typescript\n// app.module.ts\nimport { Module } from '@nestjs/common';\nimport { ConfigModule } from '@nestjs/config';\nimport { PassportModule } from '@nestjs/passport';\nimport { KeycloakStrategy, JwtAuthGuard } from '@azerothian/keycloak-api/auth';\n\n@Module({\n  imports: [\n    ConfigModule.forRoot(),\n    PassportModule.register({ defaultStrategy: 'keycloak' }),\n  ],\n  providers: [KeycloakStrategy, JwtAuthGuard],\n})\nexport class AppModule {}\n```\n\nSet environment variables:\n\n```bash\nKEYCLOAK_URL=https://keycloak.example.com\nKEYCLOAK_REALM=your-realm\n```\n\nProtect routes with the guard:\n\n```typescript\n// users.controller.ts\nimport { Controller, Get, UseGuards } from '@nestjs/common';\nimport { JwtAuthGuard, CurrentUser, Public } from '@azerothian/keycloak-api/auth';\nimport { AuthenticatedUser } from '@azerothian/keycloak-api/types';\n\n@Controller('users')\n@UseGuards(JwtAuthGuard)\nexport class UsersController {\n  @Get('profile')\n  getProfile(@CurrentUser() user: AuthenticatedUser) {\n    return {\n      keycloakId: user.keycloakId,\n      username: user.username,\n      roles: user.roles,\n    };\n  }\n\n  @Get('health')\n  @Public()\n  healthCheck() {\n    return { status: 'ok' };\n  }\n}\n```\n\n### 2. Admin API Setup\n\nImport the admin module to manage realms, users, groups, and roles:\n\n```typescript\n// app.module.ts\nimport { Module } from '@nestjs/common';\nimport { ConfigModule } from '@nestjs/config';\nimport { KeycloakAdminModule } from '@azerothian/keycloak-api/admin';\n\n@Module({\n  imports: [\n    ConfigModule.forRoot(),\n    KeycloakAdminModule,\n  ],\n})\nexport class AppModule {}\n```\n\nSet admin credentials in environment:\n\n```bash\nKEYCLOAK_URL=https://keycloak.example.com\nKEYCLOAK_ADMIN_USERNAME=admin\nKEYCLOAK_ADMIN_PASSWORD=password\nKEYCLOAK_ADMIN_CLIENT_ID=admin-cli\nKEYCLOAK_ADMIN_CLIENT_SECRET=your-client-secret\n```\n\nUse the service in your application:\n\n```typescript\n// realms.service.ts\nimport { Injectable } from '@nestjs/common';\nimport { KeycloakAdminService } from '@azerothian/keycloak-api/admin';\n\n@Injectable()\nexport class RealmsService {\n  constructor(private kcAdmin: KeycloakAdminService) {}\n\n  async getAllRealms() {\n    return this.kcAdmin.getRealms();\n  }\n\n  async getRealmUsers(realmName: string) {\n    return this.kcAdmin.getUsers(realmName, { max: 100 });\n  }\n\n  async createUser(realmName: string, user: any) {\n    return this.kcAdmin.createUser(realmName, user);\n  }\n}\n```\n\n### 3. Using Decorators\n\nControl access with decorators:\n\n```typescript\nimport { Controller, Post, UseGuards } from '@nestjs/common';\nimport { JwtAuthGuard, Permissions, CurrentUser } from '@azerothian/keycloak-api';\nimport { AuthenticatedUser } from '@azerothian/keycloak-api/types';\n\n@Controller('networks')\n@UseGuards(JwtAuthGuard)\nexport class NetworksController {\n  @Post()\n  @Permissions('networks:create')\n  createNetwork(@CurrentUser() user: AuthenticatedUser, @Body() dto: CreateNetworkDto) {\n    return {\n      createdBy: user.keycloakId,\n      ...dto,\n    };\n  }\n}\n```\n\n## Environment Variables\n\n| Variable | Description | Example |\n|----------|-------------|---------|\n| `KEYCLOAK_URL` | Base URL of Keycloak instance | `https://keycloak.example.com` |\n| `KEYCLOAK_REALM` | Primary realm for authentication | `wirenet` |\n| `KEYCLOAK_ADMIN_USERNAME` | Admin account username (for admin API) | `admin` |\n| `KEYCLOAK_ADMIN_PASSWORD` | Admin account password (for admin API) | `password` |\n| `KEYCLOAK_ADMIN_CLIENT_ID` | Client ID for admin API authentication | `admin-cli` |\n| `KEYCLOAK_ADMIN_CLIENT_SECRET` | Client secret for admin API (if using client credentials flow) | `secret-key` |\n\n## Subpath Imports\n\nThis package exports specialized modules. Import only what you need:\n\n| Import Path | Exports | Purpose |\n|-------------|---------|---------|\n| `@azerothian/keycloak-api` | All exports | Root barrel - re-exports everything |\n| `@azerothian/keycloak-api/admin` | `KeycloakAdminService`, `KeycloakAdminModule` | Keycloak Admin REST API |\n| `@azerothian/keycloak-api/auth` | `KeycloakStrategy`, `JwtAuthGuard` | JWT authentication via Passport |\n| `@azerothian/keycloak-api/decorators` | `CurrentUser()`, `Public()`, `Permissions()`, constants | Route protection decorators |\n| `@azerothian/keycloak-api/types` | `KeycloakTokenPayload`, `AuthenticatedUser`, session/event types, `SERVICE_PERMISSIONS` | Type definitions |\n| `@azerothian/keycloak-api/testing` | `TestJwtStrategy`, mock token factories | Integration testing utilities |\n\n## Testing\n\nCreate mock JWT tokens for integration tests without a running Keycloak instance:\n\n```typescript\nimport { Test } from '@nestjs/testing';\nimport {\n  TestJwtStrategy,\n  createAdminToken,\n  createUserToken,\n} from '@azerothian/keycloak-api/testing';\n\ndescribe('UsersController (e2e)', () => {\n  let app: INestApplication;\n\n  beforeAll(async () => {\n    const moduleFixture = await Test.createTestingModule({\n      controllers: [UsersController],\n      providers: [UsersService, TestJwtStrategy],\n    }).compile();\n\n    app = moduleFixture.createNestApplication();\n    await app.init();\n  });\n\n  it('should allow admin to access protected route', async () => {\n    const adminToken = createAdminToken('user-id-123', 'realm-id-456');\n\n    return request(app.getHttpServer())\n      .get('/users/profile')\n      .set('Authorization', `Bearer ${adminToken}`)\n      .expect(200);\n  });\n\n  it('should allow regular user with limited permissions', async () => {\n    const userToken = createUserToken('user-id-789', 'realm-id-456');\n\n    return request(app.getHttpServer())\n      .get('/users/profile')\n      .set('Authorization', `Bearer ${userToken}`)\n      .expect(200);\n  });\n});\n```\n\nMock token factories create tokens with predefined roles and permissions:\n\n- `createAdminToken()` - Full system access (admin role with all permissions)\n- `createUserToken()` - Regular user access (limited permissions)\n- `createPowerUserToken()` - Elevated permissions\n- `createServiceAccountToken()` - For service-to-service authentication\n- `createSuperadminToken()` - Maximum privileges (superadmin + admin roles)\n- `createMockJwtToken(payload, secret)` - Custom token with arbitrary payload\n\n## License\n\nMIT\n","readmeFilename":"README.md","_rev":"1-4a47c5c10d2ba57b99d3e872a35c10f7"}