@adatechnology/auth-keycloak 0.0.2 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,103 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.RolesGuard = void 0;
16
+ const common_1 = require("@nestjs/common");
17
+ const core_1 = require("@nestjs/core");
18
+ const roles_decorator_1 = require("./roles.decorator");
19
+ const keycloak_token_1 = require("./keycloak.token");
20
+ const shared_1 = require("@adatechnology/shared");
21
+ let RolesGuard = class RolesGuard {
22
+ reflector;
23
+ config;
24
+ constructor(reflector, config) {
25
+ this.reflector = reflector;
26
+ this.config = config;
27
+ }
28
+ canActivate(context) {
29
+ const meta = this.reflector.get(roles_decorator_1.ROLES_META_KEY, context.getHandler()) ||
30
+ this.reflector.get(roles_decorator_1.ROLES_META_KEY, context.getClass());
31
+ if (!meta || !meta.roles || meta.roles.length === 0)
32
+ return true;
33
+ const req = context.switchToHttp().getRequest();
34
+ const authHeader = req.headers?.authorization || req.headers?.Authorization;
35
+ const token = authHeader
36
+ ? String(authHeader).split(" ")[1]
37
+ : req.query?.token;
38
+ if (!token)
39
+ throw new shared_1.BaseAppError({
40
+ message: "Authorization token not provided",
41
+ status: 403,
42
+ code: "FORBIDDEN_MISSING_TOKEN",
43
+ context: {},
44
+ });
45
+ const payload = this.decodeJwtPayload(token);
46
+ const availableRoles = new Set();
47
+ // realm roles
48
+ if (payload?.realm_access?.roles &&
49
+ Array.isArray(payload.realm_access.roles)) {
50
+ payload.realm_access.roles.forEach((r) => availableRoles.add(r));
51
+ }
52
+ // client roles (resource_access)
53
+ const clientId = this.config?.credentials?.clientId;
54
+ if (clientId && payload?.resource_access?.[clientId]?.roles) {
55
+ payload.resource_access[clientId].roles.forEach((r) => availableRoles.add(r));
56
+ }
57
+ // also consider all client roles if type is 'both' and resource_access exists
58
+ if (meta.type === "both" && payload?.resource_access) {
59
+ Object.values(payload.resource_access).forEach((entry) => {
60
+ if (entry?.roles && Array.isArray(entry.roles)) {
61
+ entry.roles.forEach((r) => availableRoles.add(r));
62
+ }
63
+ });
64
+ }
65
+ // matching
66
+ const required = meta.roles || [];
67
+ const hasMatch = required.map((r) => availableRoles.has(r));
68
+ const result = meta.mode === "all" ? hasMatch.every(Boolean) : hasMatch.some(Boolean);
69
+ if (!result)
70
+ throw new shared_1.BaseAppError({
71
+ message: "Insufficient roles",
72
+ status: 403,
73
+ code: "FORBIDDEN_INSUFFICIENT_ROLES",
74
+ context: { required: required },
75
+ });
76
+ return true;
77
+ }
78
+ decodeJwtPayload(token) {
79
+ try {
80
+ const parts = token.split(".");
81
+ if (parts.length < 2)
82
+ return {};
83
+ const payload = parts[1];
84
+ const BufferCtor = globalThis.Buffer;
85
+ if (!BufferCtor)
86
+ return {};
87
+ const decoded = BufferCtor.from(payload, "base64").toString("utf8");
88
+ return JSON.parse(decoded);
89
+ }
90
+ catch (e) {
91
+ return {};
92
+ }
93
+ }
94
+ };
95
+ exports.RolesGuard = RolesGuard;
96
+ exports.RolesGuard = RolesGuard = __decorate([
97
+ (0, common_1.Injectable)(),
98
+ __param(0, (0, common_1.Inject)(core_1.Reflector)),
99
+ __param(1, (0, common_1.Optional)()),
100
+ __param(1, (0, common_1.Inject)(keycloak_token_1.KEYCLOAK_CONFIG)),
101
+ __metadata("design:paramtypes", [core_1.Reflector, Object])
102
+ ], RolesGuard);
103
+ //# sourceMappingURL=roles.guard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"roles.guard.js","sourceRoot":"","sources":["../src/roles.guard.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adatechnology/auth-keycloak",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -11,7 +11,9 @@
11
11
  "dist"
12
12
  ],
13
13
  "dependencies": {
14
- "@adatechnology/http-client": "^0.0.2"
14
+ "@adatechnology/http-client": "0.0.3",
15
+ "@adatechnology/logger": "0.0.2",
16
+ "@adatechnology/shared": "0.0.1"
15
17
  },
16
18
  "peerDependencies": {
17
19
  "@nestjs/common": "^11.0.16",
@@ -23,7 +25,7 @@
23
25
  "typescript": "^5.2.0"
24
26
  },
25
27
  "scripts": {
26
- "build": "tsup",
28
+ "build": "rm -rf dist && tsc -p tsconfig.build.json",
27
29
  "build:watch": "tsup --watch",
28
30
  "check": "tsc -p tsconfig.json --noEmit",
29
31
  "test": "echo \"no tests\""
package/dist/index.d.mts DELETED
@@ -1,65 +0,0 @@
1
- import { DynamicModule } from '@nestjs/common';
2
- import { AxiosRequestConfig, AxiosInstance } from 'axios';
3
-
4
- /**
5
- * Keycloak token response
6
- */
7
- interface KeycloakTokenResponse {
8
- access_token: string;
9
- expires_in: number;
10
- refresh_expires_in: number;
11
- refresh_token: string;
12
- token_type: string;
13
- 'not-before-policy': number;
14
- session_state: string;
15
- scope: string;
16
- }
17
- /**
18
- * Keycloak client credentials
19
- */
20
- interface KeycloakCredentials {
21
- clientId: string;
22
- clientSecret: string;
23
- username?: string;
24
- password?: string;
25
- grantType: 'client_credentials' | 'password';
26
- }
27
- /**
28
- * Keycloak configuration
29
- */
30
- interface KeycloakConfig {
31
- baseUrl: string;
32
- realm: string;
33
- credentials: KeycloakCredentials;
34
- }
35
- /**
36
- * Keycloak client interface
37
- */
38
- interface KeycloakClientInterface {
39
- /**
40
- * Get access token
41
- */
42
- getAccessToken(): Promise<string>;
43
- /**
44
- * Refresh access token
45
- */
46
- refreshToken(refreshToken: string): Promise<KeycloakTokenResponse>;
47
- /**
48
- * Validate token
49
- */
50
- validateToken(token: string): Promise<boolean>;
51
- /**
52
- * Get user info
53
- */
54
- getUserInfo(token: string): Promise<any>;
55
- }
56
-
57
- declare class KeycloakModule {
58
- static forRoot(config: KeycloakConfig, httpConfig?: AxiosRequestConfig | AxiosInstance): DynamicModule;
59
- }
60
-
61
- declare const KEYCLOAK_CONFIG = "KEYCLOAK_CONFIG";
62
- declare const KEYCLOAK_CLIENT = "KEYCLOAK_CLIENT";
63
- declare const KEYCLOAK_HTTP_INTERCEPTOR = "KEYCLOAK_HTTP_INTERCEPTOR";
64
-
65
- export { KEYCLOAK_CLIENT, KEYCLOAK_CONFIG, KEYCLOAK_HTTP_INTERCEPTOR, type KeycloakClientInterface, type KeycloakConfig, KeycloakModule, type KeycloakTokenResponse };
package/dist/index.mjs DELETED
@@ -1,200 +0,0 @@
1
- var __defProp = Object.defineProperty;
2
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
- var __decorateClass = (decorators, target, key, kind) => {
4
- var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
5
- for (var i = decorators.length - 1, decorator; i >= 0; i--)
6
- if (decorator = decorators[i])
7
- result = (kind ? decorator(target, key, result) : decorator(result)) || result;
8
- if (kind && result) __defProp(target, key, result);
9
- return result;
10
- };
11
- var __decorateParam = (index, decorator) => (target, key) => decorator(target, key, index);
12
-
13
- // src/keycloak.module.ts
14
- import { Module } from "@nestjs/common";
15
- import { HTTP_PROVIDER as HTTP_PROVIDER2, HttpModule } from "@adatechnology/http-client";
16
-
17
- // src/keycloak.client.ts
18
- import { Inject, Injectable } from "@nestjs/common";
19
- import { HTTP_PROVIDER } from "@adatechnology/http-client";
20
- var KeycloakClient = class {
21
- constructor(config, httpProvider) {
22
- this.config = config;
23
- this.httpProvider = httpProvider;
24
- }
25
- tokenCache = null;
26
- tokenPromise = null;
27
- async getAccessToken() {
28
- const now = Date.now();
29
- if (this.tokenCache && now < this.tokenCache.expiresAt) {
30
- return this.tokenCache.token;
31
- }
32
- if (this.tokenPromise) return this.tokenPromise;
33
- this.tokenPromise = (async () => {
34
- try {
35
- const tokenResponse = await this.requestToken();
36
- const expiresAt = Date.now() + (tokenResponse.expires_in - 60) * 1e3;
37
- this.tokenCache = { token: tokenResponse.access_token, expiresAt };
38
- return tokenResponse.access_token;
39
- } finally {
40
- this.tokenPromise = null;
41
- }
42
- })();
43
- return this.tokenPromise;
44
- }
45
- async getTokenWithCredentials(username, password) {
46
- const tokenUrl = `${this.config.baseUrl}/realms/${this.config.realm}/protocol/openid-connect/token`;
47
- const data = new URLSearchParams();
48
- data.append("client_id", this.config.credentials.clientId);
49
- data.append("grant_type", "password");
50
- data.append("username", username);
51
- data.append("password", password);
52
- if (this.config.credentials.clientSecret) {
53
- data.append("client_secret", this.config.credentials.clientSecret);
54
- }
55
- const response = await this.httpProvider.post(tokenUrl, data, {
56
- headers: { "Content-Type": "application/x-www-form-urlencoded" }
57
- });
58
- return response.data;
59
- }
60
- async requestToken() {
61
- const tokenUrl = `${this.config.baseUrl}/realms/${this.config.realm}/protocol/openid-connect/token`;
62
- const data = new URLSearchParams();
63
- data.append("client_id", this.config.credentials.clientId);
64
- data.append("grant_type", this.config.credentials.grantType);
65
- if (this.config.credentials.clientSecret) {
66
- data.append("client_secret", this.config.credentials.clientSecret);
67
- }
68
- if (this.config.credentials.grantType === "password") {
69
- if (this.config.credentials.username && this.config.credentials.password) {
70
- data.append("username", this.config.credentials.username);
71
- data.append("password", this.config.credentials.password);
72
- }
73
- }
74
- const response = await this.httpProvider.post(
75
- tokenUrl,
76
- data,
77
- {
78
- headers: { "Content-Type": "application/x-www-form-urlencoded" }
79
- }
80
- );
81
- return response.data;
82
- }
83
- async refreshToken(refreshToken) {
84
- const tokenUrl = `${this.config.baseUrl}/realms/${this.config.realm}/protocol/openid-connect/token`;
85
- const data = new URLSearchParams();
86
- data.append("client_id", this.config.credentials.clientId);
87
- data.append("grant_type", "refresh_token");
88
- data.append("refresh_token", refreshToken);
89
- if (this.config.credentials.clientSecret) {
90
- data.append("client_secret", this.config.credentials.clientSecret);
91
- }
92
- const response = await this.httpProvider.post(
93
- tokenUrl,
94
- data,
95
- {
96
- headers: { "Content-Type": "application/x-www-form-urlencoded" }
97
- }
98
- );
99
- const expiresAt = Date.now() + (response.data.expires_in - 60) * 1e3;
100
- this.tokenCache = { token: response.data.access_token, expiresAt };
101
- return response.data;
102
- }
103
- async validateToken(token) {
104
- try {
105
- const introspectUrl = `${this.config.baseUrl}/realms/${this.config.realm}/protocol/openid-connect/token/introspect`;
106
- const data = new URLSearchParams();
107
- data.append("token", token);
108
- data.append("client_id", this.config.credentials.clientId);
109
- if (this.config.credentials.clientSecret) {
110
- data.append("client_secret", this.config.credentials.clientSecret);
111
- }
112
- const response = await this.httpProvider.post(introspectUrl, data, {
113
- headers: { "Content-Type": "application/x-www-form-urlencoded" }
114
- });
115
- return response.data.active === true;
116
- } catch (error) {
117
- return false;
118
- }
119
- }
120
- async getUserInfo(token) {
121
- const userInfoUrl = `${this.config.baseUrl}/realms/${this.config.realm}/protocol/openid-connect/userinfo`;
122
- const response = await this.httpProvider.get(userInfoUrl, {
123
- headers: { Authorization: `Bearer ${token}` }
124
- });
125
- return response.data;
126
- }
127
- clearTokenCache() {
128
- this.tokenCache = null;
129
- }
130
- static maskToken(token, visibleChars = 8) {
131
- if (!token || typeof token !== "string") return "";
132
- return token.length <= visibleChars ? token : `${token.slice(0, visibleChars)}...`;
133
- }
134
- };
135
- KeycloakClient = __decorateClass([
136
- Injectable(),
137
- __decorateParam(1, Inject(HTTP_PROVIDER))
138
- ], KeycloakClient);
139
-
140
- // src/keycloak.http.interceptor.ts
141
- import {
142
- Inject as Inject2,
143
- Injectable as Injectable2
144
- } from "@nestjs/common";
145
-
146
- // src/keycloak.token.ts
147
- var KEYCLOAK_CONFIG = "KEYCLOAK_CONFIG";
148
- var KEYCLOAK_CLIENT = "KEYCLOAK_CLIENT";
149
- var KEYCLOAK_HTTP_INTERCEPTOR = "KEYCLOAK_HTTP_INTERCEPTOR";
150
-
151
- // src/keycloak.http.interceptor.ts
152
- var KeycloakHttpInterceptor = class {
153
- constructor(keycloakClient) {
154
- this.keycloakClient = keycloakClient;
155
- }
156
- intercept(context, next) {
157
- const request = context.switchToHttp().getRequest();
158
- if (request.url && !request.url.includes("keycloak")) {
159
- }
160
- return next.handle();
161
- }
162
- };
163
- KeycloakHttpInterceptor = __decorateClass([
164
- Injectable2(),
165
- __decorateParam(0, Inject2(KEYCLOAK_CLIENT))
166
- ], KeycloakHttpInterceptor);
167
-
168
- // src/keycloak.module.ts
169
- var KeycloakModule = class {
170
- static forRoot(config, httpConfig) {
171
- return {
172
- module: KeycloakModule,
173
- global: true,
174
- imports: [HttpModule.forRoot(httpConfig)],
175
- providers: [
176
- { provide: KEYCLOAK_CONFIG, useValue: config },
177
- {
178
- provide: KEYCLOAK_CLIENT,
179
- useFactory: (cfg, httpProvider) => new KeycloakClient(cfg, httpProvider),
180
- inject: [KEYCLOAK_CONFIG, HTTP_PROVIDER2]
181
- },
182
- {
183
- provide: KEYCLOAK_HTTP_INTERCEPTOR,
184
- useFactory: (client) => new KeycloakHttpInterceptor(client),
185
- inject: [KEYCLOAK_CLIENT]
186
- }
187
- ],
188
- exports: [KEYCLOAK_CLIENT, KEYCLOAK_HTTP_INTERCEPTOR]
189
- };
190
- }
191
- };
192
- KeycloakModule = __decorateClass([
193
- Module({})
194
- ], KeycloakModule);
195
- export {
196
- KEYCLOAK_CLIENT,
197
- KEYCLOAK_CONFIG,
198
- KEYCLOAK_HTTP_INTERCEPTOR,
199
- KeycloakModule
200
- };