@adatechnology/auth-keycloak 0.0.8 → 0.1.0
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.
- package/README.md +31 -1
- package/dist/index.d.ts +28 -1
- package/dist/index.js +205 -52
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -10,7 +10,8 @@ e um interceptor opcional. O módulo foi projetado para ser usado junto ao `@ada
|
|
|
10
10
|
- `KeycloakModule` — módulo principal. Suporta `KeycloakModule.forRoot(config?)`.
|
|
11
11
|
- `KEYCLOAK_CLIENT` — provider token para injetar o cliente Keycloak (`@Inject(KEYCLOAK_CLIENT)`).
|
|
12
12
|
- `KEYCLOAK_HTTP_INTERCEPTOR` — provider token para injetar o interceptor (opcional).
|
|
13
|
-
- `
|
|
13
|
+
- `BearerTokenGuard` — guard que valida o token Bearer via introspecção no Keycloak (401 em falha).
|
|
14
|
+
- `Roles` / `RolesGuard` — decorator e guard para autorização baseada em roles (403 em falha).
|
|
14
15
|
- `KeycloakError` — classe de erro tipada com `statusCode` e `details`.
|
|
15
16
|
|
|
16
17
|
### Instalação
|
|
@@ -128,6 +129,35 @@ Resultado no log:
|
|
|
128
129
|
[MyController.getToken][InMemoryCacheProvider.set] → token cached
|
|
129
130
|
```
|
|
130
131
|
|
|
132
|
+
### BearerTokenGuard — autenticação B2B via introspecção
|
|
133
|
+
|
|
134
|
+
Valida que o header `Authorization: Bearer <token>` contém um token ativo chamando
|
|
135
|
+
`POST /token/introspect` no Keycloak. Use sempre em conjunto com `RolesGuard` em rotas B2B.
|
|
136
|
+
|
|
137
|
+
```ts
|
|
138
|
+
import { Controller, Headers, Post, UseGuards } from "@nestjs/common";
|
|
139
|
+
import { BearerTokenGuard, Roles, RolesGuard } from "@adatechnology/auth-keycloak";
|
|
140
|
+
|
|
141
|
+
@Controller("orders")
|
|
142
|
+
export class OrdersController {
|
|
143
|
+
@Post()
|
|
144
|
+
@Roles("manage-requests")
|
|
145
|
+
@UseGuards(BearerTokenGuard, RolesGuard)
|
|
146
|
+
create(@Headers("x-user-id") keycloakId: string) {}
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
**Por que dois guards em sequência?**
|
|
151
|
+
|
|
152
|
+
| Guard | Mecanismo | HTTP? | Falha |
|
|
153
|
+
|---|---|---|---|
|
|
154
|
+
| `BearerTokenGuard` | `POST /token/introspect` ao Keycloak | Sim | 401 — token inativo/expirado/forjado |
|
|
155
|
+
| `RolesGuard` | Decode local do payload JWT | Não | 403 — permissão insuficiente |
|
|
156
|
+
|
|
157
|
+
O `RolesGuard` sozinho **não é seguro** para autenticação: ele apenas decodifica o payload JWT
|
|
158
|
+
sem verificar a assinatura, o que significa que um token forjado passaria. O `BearerTokenGuard`
|
|
159
|
+
é quem garante autenticidade via introspecção.
|
|
160
|
+
|
|
131
161
|
### Autorização com @Roles
|
|
132
162
|
|
|
133
163
|
```ts
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as _nestjs_common from '@nestjs/common';
|
|
2
2
|
import { DynamicModule, CanActivate, ExecutionContext } from '@nestjs/common';
|
|
3
3
|
import { AxiosRequestConfig, AxiosInstance } from 'axios';
|
|
4
|
+
import { LoggerProviderInterface } from '@adatechnology/logger';
|
|
4
5
|
import { Reflector } from '@nestjs/core';
|
|
5
6
|
|
|
6
7
|
/**
|
|
@@ -87,6 +88,32 @@ declare class KeycloakModule {
|
|
|
87
88
|
static forRoot(config: KeycloakConfig, httpConfig?: AxiosRequestConfig | AxiosInstance): DynamicModule;
|
|
88
89
|
}
|
|
89
90
|
|
|
91
|
+
/**
|
|
92
|
+
* Guard that validates the Bearer token in the Authorization header via
|
|
93
|
+
* Keycloak token introspection (POST /token/introspect).
|
|
94
|
+
*
|
|
95
|
+
* Use together with RolesGuard for B2B (service-to-service) routes that trust
|
|
96
|
+
* an X-User-Id header injected by an upstream authenticated service:
|
|
97
|
+
*
|
|
98
|
+
* @example
|
|
99
|
+
* ```ts
|
|
100
|
+
* @Roles('manage-requests')
|
|
101
|
+
* @UseGuards(BearerTokenGuard, RolesGuard)
|
|
102
|
+
* async create(@Headers('x-user-id') keycloakId: string) {}
|
|
103
|
+
* ```
|
|
104
|
+
*
|
|
105
|
+
* Execution order:
|
|
106
|
+
* 1. BearerTokenGuard — validates token is active (HTTP → Keycloak) → 401 on failure
|
|
107
|
+
* 2. RolesGuard — checks roles from decoded JWT payload (local) → 403 on failure
|
|
108
|
+
*/
|
|
109
|
+
declare class BearerTokenGuard implements CanActivate {
|
|
110
|
+
private readonly keycloakClient?;
|
|
111
|
+
private readonly logger?;
|
|
112
|
+
constructor(keycloakClient?: KeycloakClientInterface, logger?: LoggerProviderInterface);
|
|
113
|
+
private log;
|
|
114
|
+
canActivate(context: ExecutionContext): Promise<boolean>;
|
|
115
|
+
}
|
|
116
|
+
|
|
90
117
|
declare const KEYCLOAK_CONFIG = "KEYCLOAK_CONFIG";
|
|
91
118
|
declare const KEYCLOAK_CLIENT = "KEYCLOAK_CLIENT";
|
|
92
119
|
declare const KEYCLOAK_HTTP_INTERCEPTOR = "KEYCLOAK_HTTP_INTERCEPTOR";
|
|
@@ -129,4 +156,4 @@ declare class KeycloakError extends Error {
|
|
|
129
156
|
});
|
|
130
157
|
}
|
|
131
158
|
|
|
132
|
-
export { KEYCLOAK_CLIENT, KEYCLOAK_CONFIG, KEYCLOAK_HTTP_INTERCEPTOR, KEYCLOAK_PROVIDER, type KeycloakClientInterface, type KeycloakConfig, KeycloakError, KeycloakModule, type KeycloakProviderInterface, type KeycloakTokenResponse, Roles, RolesGuard };
|
|
159
|
+
export { BearerTokenGuard, KEYCLOAK_CLIENT, KEYCLOAK_CONFIG, KEYCLOAK_HTTP_INTERCEPTOR, KEYCLOAK_PROVIDER, type KeycloakClientInterface, type KeycloakConfig, KeycloakError, KeycloakModule, type KeycloakProviderInterface, type KeycloakTokenResponse, Roles, RolesGuard };
|
package/dist/index.js
CHANGED
|
@@ -68,7 +68,7 @@ var require_base_app_error = __commonJS({
|
|
|
68
68
|
"use strict";
|
|
69
69
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
70
70
|
exports2.BaseAppError = void 0;
|
|
71
|
-
var
|
|
71
|
+
var BaseAppError3 = class extends Error {
|
|
72
72
|
code;
|
|
73
73
|
status;
|
|
74
74
|
context;
|
|
@@ -83,7 +83,7 @@ var require_base_app_error = __commonJS({
|
|
|
83
83
|
(_a = capturable.captureStackTrace) == null ? void 0 : _a.call(capturable, this, this.constructor);
|
|
84
84
|
}
|
|
85
85
|
};
|
|
86
|
-
exports2.BaseAppError =
|
|
86
|
+
exports2.BaseAppError = BaseAppError3;
|
|
87
87
|
}
|
|
88
88
|
});
|
|
89
89
|
|
|
@@ -268,6 +268,7 @@ var require_dist = __commonJS({
|
|
|
268
268
|
// src/index.ts
|
|
269
269
|
var index_exports = {};
|
|
270
270
|
__export(index_exports, {
|
|
271
|
+
BearerTokenGuard: () => BearerTokenGuard,
|
|
271
272
|
KEYCLOAK_CLIENT: () => KEYCLOAK_CLIENT,
|
|
272
273
|
KEYCLOAK_CONFIG: () => KEYCLOAK_CONFIG,
|
|
273
274
|
KEYCLOAK_HTTP_INTERCEPTOR: () => KEYCLOAK_HTTP_INTERCEPTOR,
|
|
@@ -280,16 +281,174 @@ __export(index_exports, {
|
|
|
280
281
|
module.exports = __toCommonJS(index_exports);
|
|
281
282
|
|
|
282
283
|
// src/keycloak.module.ts
|
|
283
|
-
var
|
|
284
|
+
var import_common6 = require("@nestjs/common");
|
|
284
285
|
var import_core2 = require("@nestjs/core");
|
|
285
|
-
var
|
|
286
|
-
var
|
|
286
|
+
var import_http_client3 = require("@adatechnology/http-client");
|
|
287
|
+
var import_logger3 = require("@adatechnology/logger");
|
|
287
288
|
var import_cache3 = require("@adatechnology/cache");
|
|
288
289
|
|
|
289
|
-
// src/
|
|
290
|
+
// src/bearer-token.guard.ts
|
|
290
291
|
var import_common = require("@nestjs/common");
|
|
291
|
-
var import_http_client = require("@adatechnology/http-client");
|
|
292
292
|
var import_logger = require("@adatechnology/logger");
|
|
293
|
+
var import_http_client = require("@adatechnology/http-client");
|
|
294
|
+
var import_shared = __toESM(require_dist());
|
|
295
|
+
|
|
296
|
+
// src/keycloak.token.ts
|
|
297
|
+
var KEYCLOAK_CONFIG = "KEYCLOAK_CONFIG";
|
|
298
|
+
var KEYCLOAK_CLIENT = "KEYCLOAK_CLIENT";
|
|
299
|
+
var KEYCLOAK_HTTP_INTERCEPTOR = "KEYCLOAK_HTTP_INTERCEPTOR";
|
|
300
|
+
var KEYCLOAK_PROVIDER = "KEYCLOAK_PROVIDER";
|
|
301
|
+
|
|
302
|
+
// package.json
|
|
303
|
+
var package_default = {
|
|
304
|
+
name: "@adatechnology/auth-keycloak",
|
|
305
|
+
version: "0.1.0",
|
|
306
|
+
publishConfig: {
|
|
307
|
+
access: "public"
|
|
308
|
+
},
|
|
309
|
+
main: "dist/index.js",
|
|
310
|
+
module: "dist/index.mjs",
|
|
311
|
+
types: "dist/index.d.ts",
|
|
312
|
+
files: [
|
|
313
|
+
"dist"
|
|
314
|
+
],
|
|
315
|
+
scripts: {
|
|
316
|
+
build: "rm -rf dist && tsup",
|
|
317
|
+
"build:watch": "tsup --watch",
|
|
318
|
+
check: "tsc -p tsconfig.json --noEmit",
|
|
319
|
+
test: 'echo "no tests"'
|
|
320
|
+
},
|
|
321
|
+
dependencies: {
|
|
322
|
+
"@adatechnology/cache": "workspace:*",
|
|
323
|
+
"@adatechnology/http-client": "workspace:*",
|
|
324
|
+
"@adatechnology/logger": "workspace:*"
|
|
325
|
+
},
|
|
326
|
+
peerDependencies: {
|
|
327
|
+
"@nestjs/common": "^11.0.16",
|
|
328
|
+
"@nestjs/core": "^11"
|
|
329
|
+
},
|
|
330
|
+
devDependencies: {
|
|
331
|
+
"@adatechnology/shared": "workspace:*",
|
|
332
|
+
"@esbuild-plugins/tsconfig-paths": "^0.1.2",
|
|
333
|
+
tsup: "^8.5.1",
|
|
334
|
+
typescript: "^5.2.0"
|
|
335
|
+
}
|
|
336
|
+
};
|
|
337
|
+
|
|
338
|
+
// src/keycloak.constants.ts
|
|
339
|
+
var LIB_NAME = package_default.name;
|
|
340
|
+
var LIB_VERSION = package_default.version;
|
|
341
|
+
var TOKEN_CACHE_KEY = "keycloak:access_token";
|
|
342
|
+
var LOG_CONTEXT = {
|
|
343
|
+
KEYCLOAK_CLIENT: "KeycloakClient",
|
|
344
|
+
BEARER_TOKEN_GUARD: "BearerTokenGuard"
|
|
345
|
+
};
|
|
346
|
+
var HTTP_STATUS = {
|
|
347
|
+
UNAUTHORIZED: 401,
|
|
348
|
+
FORBIDDEN: 403
|
|
349
|
+
};
|
|
350
|
+
var BEARER_ERROR_CODE = {
|
|
351
|
+
MISSING_TOKEN: "UNAUTHORIZED_MISSING_TOKEN",
|
|
352
|
+
KEYCLOAK_NOT_CONFIGURED: "UNAUTHORIZED_KEYCLOAK_NOT_CONFIGURED",
|
|
353
|
+
TOKEN_VALIDATION_FAILED: "UNAUTHORIZED_TOKEN_VALIDATION_FAILED",
|
|
354
|
+
INACTIVE_TOKEN: "UNAUTHORIZED_INACTIVE_TOKEN"
|
|
355
|
+
};
|
|
356
|
+
var ROLES_ERROR_CODE = {
|
|
357
|
+
MISSING_TOKEN: "FORBIDDEN_MISSING_TOKEN",
|
|
358
|
+
INSUFFICIENT_ROLES: "FORBIDDEN_INSUFFICIENT_ROLES"
|
|
359
|
+
};
|
|
360
|
+
|
|
361
|
+
// src/bearer-token.guard.ts
|
|
362
|
+
var BearerTokenGuard = class {
|
|
363
|
+
constructor(keycloakClient, logger) {
|
|
364
|
+
this.keycloakClient = keycloakClient;
|
|
365
|
+
this.logger = logger;
|
|
366
|
+
}
|
|
367
|
+
log(level, message, libMethod, meta) {
|
|
368
|
+
if (!this.logger) return;
|
|
369
|
+
const loggerCtx = (0, import_logger.getContext)();
|
|
370
|
+
const httpCtx = (0, import_http_client.getHttpRequestContext)();
|
|
371
|
+
const logContext = loggerCtx == null ? void 0 : loggerCtx.logContext;
|
|
372
|
+
const requestId = (loggerCtx == null ? void 0 : loggerCtx.requestId) ?? (httpCtx == null ? void 0 : httpCtx.requestId);
|
|
373
|
+
const source = (logContext == null ? void 0 : logContext.className) && (logContext == null ? void 0 : logContext.methodName) ? `${logContext.className}.${logContext.methodName}` : (httpCtx == null ? void 0 : httpCtx.className) && (httpCtx == null ? void 0 : httpCtx.methodName) ? `${httpCtx.className}.${httpCtx.methodName}` : void 0;
|
|
374
|
+
const payload = {
|
|
375
|
+
message,
|
|
376
|
+
context: LOG_CONTEXT.BEARER_TOKEN_GUARD,
|
|
377
|
+
lib: LIB_NAME,
|
|
378
|
+
libVersion: LIB_VERSION,
|
|
379
|
+
libMethod,
|
|
380
|
+
source,
|
|
381
|
+
requestId,
|
|
382
|
+
meta
|
|
383
|
+
};
|
|
384
|
+
if (level === "debug") this.logger.debug(payload);
|
|
385
|
+
else if (level === "info") this.logger.info(payload);
|
|
386
|
+
else if (level === "warn") this.logger.warn(payload);
|
|
387
|
+
else if (level === "error") this.logger.error(payload);
|
|
388
|
+
}
|
|
389
|
+
async canActivate(context) {
|
|
390
|
+
var _a, _b;
|
|
391
|
+
const method = "canActivate";
|
|
392
|
+
this.log("debug", `${method} - Start`, method);
|
|
393
|
+
const request = context.switchToHttp().getRequest();
|
|
394
|
+
const authorization = ((_a = request.headers) == null ? void 0 : _a.authorization) ?? ((_b = request.headers) == null ? void 0 : _b.Authorization);
|
|
395
|
+
if (!(authorization == null ? void 0 : authorization.startsWith("Bearer "))) {
|
|
396
|
+
this.log("warn", `${method} - Missing or invalid Authorization header`, method);
|
|
397
|
+
throw new import_shared.BaseAppError({
|
|
398
|
+
message: "Missing or invalid Authorization header",
|
|
399
|
+
status: HTTP_STATUS.UNAUTHORIZED,
|
|
400
|
+
code: BEARER_ERROR_CODE.MISSING_TOKEN,
|
|
401
|
+
context: {}
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
if (!this.keycloakClient) {
|
|
405
|
+
this.log("error", `${method} - Keycloak client not configured`, method);
|
|
406
|
+
throw new import_shared.BaseAppError({
|
|
407
|
+
message: "Keycloak client not configured",
|
|
408
|
+
status: HTTP_STATUS.UNAUTHORIZED,
|
|
409
|
+
code: BEARER_ERROR_CODE.KEYCLOAK_NOT_CONFIGURED,
|
|
410
|
+
context: {}
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
const token = authorization.slice(7);
|
|
414
|
+
let isValid;
|
|
415
|
+
try {
|
|
416
|
+
isValid = await this.keycloakClient.validateToken(token);
|
|
417
|
+
} catch (err) {
|
|
418
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
419
|
+
this.log("error", `${method} - Token validation failed`, method, { detail });
|
|
420
|
+
throw new import_shared.BaseAppError({
|
|
421
|
+
message: "Token validation failed",
|
|
422
|
+
status: HTTP_STATUS.UNAUTHORIZED,
|
|
423
|
+
code: BEARER_ERROR_CODE.TOKEN_VALIDATION_FAILED,
|
|
424
|
+
context: { detail }
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
if (!isValid) {
|
|
428
|
+
this.log("warn", `${method} - Inactive or expired token`, method);
|
|
429
|
+
throw new import_shared.BaseAppError({
|
|
430
|
+
message: "Inactive or expired token",
|
|
431
|
+
status: HTTP_STATUS.UNAUTHORIZED,
|
|
432
|
+
code: BEARER_ERROR_CODE.INACTIVE_TOKEN,
|
|
433
|
+
context: {}
|
|
434
|
+
});
|
|
435
|
+
}
|
|
436
|
+
this.log("debug", `${method} - Token valid`, method);
|
|
437
|
+
return true;
|
|
438
|
+
}
|
|
439
|
+
};
|
|
440
|
+
BearerTokenGuard = __decorateClass([
|
|
441
|
+
(0, import_common.Injectable)(),
|
|
442
|
+
__decorateParam(0, (0, import_common.Optional)()),
|
|
443
|
+
__decorateParam(0, (0, import_common.Inject)(KEYCLOAK_CLIENT)),
|
|
444
|
+
__decorateParam(1, (0, import_common.Optional)()),
|
|
445
|
+
__decorateParam(1, (0, import_common.Inject)(import_logger.LOGGER_PROVIDER))
|
|
446
|
+
], BearerTokenGuard);
|
|
447
|
+
|
|
448
|
+
// src/keycloak.client.ts
|
|
449
|
+
var import_common2 = require("@nestjs/common");
|
|
450
|
+
var import_http_client2 = require("@adatechnology/http-client");
|
|
451
|
+
var import_logger2 = require("@adatechnology/logger");
|
|
293
452
|
var import_cache = require("@adatechnology/cache");
|
|
294
453
|
var import_cache2 = require("@adatechnology/cache");
|
|
295
454
|
|
|
@@ -309,9 +468,6 @@ var KeycloakError = class _KeycloakError extends Error {
|
|
|
309
468
|
};
|
|
310
469
|
|
|
311
470
|
// src/keycloak.client.ts
|
|
312
|
-
var LIB_NAME = "@adatechnology/auth-keycloak";
|
|
313
|
-
var LIB_VERSION = "0.0.7";
|
|
314
|
-
var TOKEN_CACHE_KEY = "keycloak:access_token";
|
|
315
471
|
function extractErrorInfo(err) {
|
|
316
472
|
var _a, _b, _c, _d, _e;
|
|
317
473
|
const statusCode = (err == null ? void 0 : err.status) ?? ((_a = err == null ? void 0 : err.response) == null ? void 0 : _a.status);
|
|
@@ -347,14 +503,14 @@ var KeycloakClient = class {
|
|
|
347
503
|
tokenPromise = null;
|
|
348
504
|
log(level, message, libMethod, meta) {
|
|
349
505
|
if (!this.logger) return;
|
|
350
|
-
const loggerCtx = (0,
|
|
351
|
-
const httpCtx = (0,
|
|
506
|
+
const loggerCtx = (0, import_logger2.getContext)();
|
|
507
|
+
const httpCtx = (0, import_http_client2.getHttpRequestContext)();
|
|
352
508
|
const logContext = loggerCtx == null ? void 0 : loggerCtx.logContext;
|
|
353
509
|
const requestId = (loggerCtx == null ? void 0 : loggerCtx.requestId) ?? (httpCtx == null ? void 0 : httpCtx.requestId);
|
|
354
510
|
const source = (logContext == null ? void 0 : logContext.className) && (logContext == null ? void 0 : logContext.methodName) ? `${logContext.className}.${logContext.methodName}` : (httpCtx == null ? void 0 : httpCtx.className) && (httpCtx == null ? void 0 : httpCtx.methodName) ? `${httpCtx.className}.${httpCtx.methodName}` : void 0;
|
|
355
511
|
const payload = {
|
|
356
512
|
message,
|
|
357
|
-
context:
|
|
513
|
+
context: LOG_CONTEXT.KEYCLOAK_CLIENT,
|
|
358
514
|
lib: LIB_NAME,
|
|
359
515
|
libVersion: LIB_VERSION,
|
|
360
516
|
libMethod,
|
|
@@ -413,7 +569,7 @@ var KeycloakClient = class {
|
|
|
413
569
|
data: body,
|
|
414
570
|
config: {
|
|
415
571
|
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
416
|
-
logContext: { className:
|
|
572
|
+
logContext: { className: LOG_CONTEXT.KEYCLOAK_CLIENT, methodName: method }
|
|
417
573
|
}
|
|
418
574
|
});
|
|
419
575
|
this.log("info", `${method} - Success for user: ${username}`, method);
|
|
@@ -451,7 +607,7 @@ var KeycloakClient = class {
|
|
|
451
607
|
data,
|
|
452
608
|
config: {
|
|
453
609
|
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
454
|
-
logContext: { className:
|
|
610
|
+
logContext: { className: LOG_CONTEXT.KEYCLOAK_CLIENT, methodName: method }
|
|
455
611
|
}
|
|
456
612
|
});
|
|
457
613
|
this.log("debug", `${method} - Success`, method);
|
|
@@ -483,7 +639,7 @@ var KeycloakClient = class {
|
|
|
483
639
|
data,
|
|
484
640
|
config: {
|
|
485
641
|
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
486
|
-
logContext: { className:
|
|
642
|
+
logContext: { className: LOG_CONTEXT.KEYCLOAK_CLIENT, methodName: method }
|
|
487
643
|
}
|
|
488
644
|
});
|
|
489
645
|
const ttlSeconds = this.config.tokenCacheTtl ? Math.floor(this.config.tokenCacheTtl / 1e3) : response.data.expires_in - 60;
|
|
@@ -517,7 +673,7 @@ var KeycloakClient = class {
|
|
|
517
673
|
data,
|
|
518
674
|
config: {
|
|
519
675
|
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
520
|
-
logContext: { className:
|
|
676
|
+
logContext: { className: LOG_CONTEXT.KEYCLOAK_CLIENT, methodName: method }
|
|
521
677
|
}
|
|
522
678
|
});
|
|
523
679
|
const active = ((_a = response.data) == null ? void 0 : _a.active) === true;
|
|
@@ -542,7 +698,7 @@ var KeycloakClient = class {
|
|
|
542
698
|
url: userInfoUrl,
|
|
543
699
|
config: {
|
|
544
700
|
headers: { Authorization: `Bearer ${token}` },
|
|
545
|
-
logContext: { className:
|
|
701
|
+
logContext: { className: LOG_CONTEXT.KEYCLOAK_CLIENT, methodName: method }
|
|
546
702
|
}
|
|
547
703
|
});
|
|
548
704
|
this.log("debug", `${method} - Success`, method);
|
|
@@ -566,16 +722,16 @@ var KeycloakClient = class {
|
|
|
566
722
|
}
|
|
567
723
|
};
|
|
568
724
|
KeycloakClient = __decorateClass([
|
|
569
|
-
(0,
|
|
570
|
-
__decorateParam(1, (0,
|
|
571
|
-
__decorateParam(2, (0,
|
|
572
|
-
__decorateParam(2, (0,
|
|
573
|
-
__decorateParam(3, (0,
|
|
574
|
-
__decorateParam(3, (0,
|
|
725
|
+
(0, import_common2.Injectable)(),
|
|
726
|
+
__decorateParam(1, (0, import_common2.Inject)(import_http_client2.HTTP_PROVIDER)),
|
|
727
|
+
__decorateParam(2, (0, import_common2.Optional)()),
|
|
728
|
+
__decorateParam(2, (0, import_common2.Inject)(import_logger2.LOGGER_PROVIDER)),
|
|
729
|
+
__decorateParam(3, (0, import_common2.Optional)()),
|
|
730
|
+
__decorateParam(3, (0, import_common2.Inject)(import_cache2.CACHE_PROVIDER))
|
|
575
731
|
], KeycloakClient);
|
|
576
732
|
|
|
577
733
|
// src/keycloak.http.interceptor.ts
|
|
578
|
-
var
|
|
734
|
+
var import_common3 = require("@nestjs/common");
|
|
579
735
|
var KeycloakHttpInterceptor = class {
|
|
580
736
|
constructor() {
|
|
581
737
|
}
|
|
@@ -587,15 +743,15 @@ var KeycloakHttpInterceptor = class {
|
|
|
587
743
|
}
|
|
588
744
|
};
|
|
589
745
|
KeycloakHttpInterceptor = __decorateClass([
|
|
590
|
-
(0,
|
|
746
|
+
(0, import_common3.Injectable)()
|
|
591
747
|
], KeycloakHttpInterceptor);
|
|
592
748
|
|
|
593
749
|
// src/roles.guard.ts
|
|
594
|
-
var
|
|
750
|
+
var import_common5 = require("@nestjs/common");
|
|
595
751
|
var import_core = require("@nestjs/core");
|
|
596
752
|
|
|
597
753
|
// src/roles.decorator.ts
|
|
598
|
-
var
|
|
754
|
+
var import_common4 = require("@nestjs/common");
|
|
599
755
|
var ROLES_META_KEY = "roles";
|
|
600
756
|
function Roles(...args) {
|
|
601
757
|
let payload;
|
|
@@ -609,17 +765,11 @@ function Roles(...args) {
|
|
|
609
765
|
}
|
|
610
766
|
payload.mode = payload.mode ?? "any";
|
|
611
767
|
payload.type = payload.type ?? "both";
|
|
612
|
-
return (0,
|
|
768
|
+
return (0, import_common4.SetMetadata)(ROLES_META_KEY, payload);
|
|
613
769
|
}
|
|
614
770
|
|
|
615
|
-
// src/keycloak.token.ts
|
|
616
|
-
var KEYCLOAK_CONFIG = "KEYCLOAK_CONFIG";
|
|
617
|
-
var KEYCLOAK_CLIENT = "KEYCLOAK_CLIENT";
|
|
618
|
-
var KEYCLOAK_HTTP_INTERCEPTOR = "KEYCLOAK_HTTP_INTERCEPTOR";
|
|
619
|
-
var KEYCLOAK_PROVIDER = "KEYCLOAK_PROVIDER";
|
|
620
|
-
|
|
621
771
|
// src/roles.guard.ts
|
|
622
|
-
var
|
|
772
|
+
var import_shared2 = __toESM(require_dist());
|
|
623
773
|
var RolesGuard = class {
|
|
624
774
|
constructor(reflector, config) {
|
|
625
775
|
this.reflector = reflector;
|
|
@@ -633,10 +783,10 @@ var RolesGuard = class {
|
|
|
633
783
|
const authHeader = ((_a = req.headers) == null ? void 0 : _a.authorization) || ((_b = req.headers) == null ? void 0 : _b.Authorization);
|
|
634
784
|
const token = authHeader ? String(authHeader).split(" ")[1] : (_c = req.query) == null ? void 0 : _c.token;
|
|
635
785
|
if (!token)
|
|
636
|
-
throw new
|
|
786
|
+
throw new import_shared2.BaseAppError({
|
|
637
787
|
message: "Authorization token not provided",
|
|
638
|
-
status:
|
|
639
|
-
code:
|
|
788
|
+
status: HTTP_STATUS.FORBIDDEN,
|
|
789
|
+
code: ROLES_ERROR_CODE.MISSING_TOKEN,
|
|
640
790
|
context: {}
|
|
641
791
|
});
|
|
642
792
|
const payload = this.decodeJwtPayload(token);
|
|
@@ -663,10 +813,10 @@ var RolesGuard = class {
|
|
|
663
813
|
const hasMatch = required.map((r) => availableRoles.has(r));
|
|
664
814
|
const result = meta.mode === "all" ? hasMatch.every(Boolean) : hasMatch.some(Boolean);
|
|
665
815
|
if (!result)
|
|
666
|
-
throw new
|
|
816
|
+
throw new import_shared2.BaseAppError({
|
|
667
817
|
message: "Insufficient roles",
|
|
668
|
-
status:
|
|
669
|
-
code:
|
|
818
|
+
status: HTTP_STATUS.FORBIDDEN,
|
|
819
|
+
code: ROLES_ERROR_CODE.INSUFFICIENT_ROLES,
|
|
670
820
|
context: { required }
|
|
671
821
|
});
|
|
672
822
|
return true;
|
|
@@ -686,10 +836,10 @@ var RolesGuard = class {
|
|
|
686
836
|
}
|
|
687
837
|
};
|
|
688
838
|
RolesGuard = __decorateClass([
|
|
689
|
-
(0,
|
|
690
|
-
__decorateParam(0, (0,
|
|
691
|
-
__decorateParam(1, (0,
|
|
692
|
-
__decorateParam(1, (0,
|
|
839
|
+
(0, import_common5.Injectable)(),
|
|
840
|
+
__decorateParam(0, (0, import_common5.Inject)(import_core.Reflector)),
|
|
841
|
+
__decorateParam(1, (0, import_common5.Optional)()),
|
|
842
|
+
__decorateParam(1, (0, import_common5.Inject)(KEYCLOAK_CONFIG))
|
|
693
843
|
], RolesGuard);
|
|
694
844
|
|
|
695
845
|
// src/keycloak.module.ts
|
|
@@ -699,7 +849,7 @@ var KeycloakModule = class {
|
|
|
699
849
|
module: KeycloakModule,
|
|
700
850
|
global: true,
|
|
701
851
|
imports: [
|
|
702
|
-
|
|
852
|
+
import_http_client3.HttpModule.forRoot(
|
|
703
853
|
httpConfig || { baseURL: config.baseUrl, timeout: 5e3 },
|
|
704
854
|
{
|
|
705
855
|
logging: {
|
|
@@ -719,8 +869,8 @@ var KeycloakModule = class {
|
|
|
719
869
|
useFactory: (cfg, httpProvider, logger, cacheProvider) => new KeycloakClient(cfg, httpProvider, logger, cacheProvider),
|
|
720
870
|
inject: [
|
|
721
871
|
KEYCLOAK_CONFIG,
|
|
722
|
-
|
|
723
|
-
{ token:
|
|
872
|
+
import_http_client3.HTTP_PROVIDER,
|
|
873
|
+
{ token: import_logger3.LOGGER_PROVIDER, optional: true },
|
|
724
874
|
{ token: import_cache3.CACHE_PROVIDER, optional: true }
|
|
725
875
|
]
|
|
726
876
|
},
|
|
@@ -732,7 +882,8 @@ var KeycloakModule = class {
|
|
|
732
882
|
provide: KEYCLOAK_HTTP_INTERCEPTOR,
|
|
733
883
|
useFactory: () => new KeycloakHttpInterceptor()
|
|
734
884
|
},
|
|
735
|
-
RolesGuard
|
|
885
|
+
RolesGuard,
|
|
886
|
+
BearerTokenGuard
|
|
736
887
|
],
|
|
737
888
|
exports: [
|
|
738
889
|
import_core2.Reflector,
|
|
@@ -740,16 +891,18 @@ var KeycloakModule = class {
|
|
|
740
891
|
KEYCLOAK_PROVIDER,
|
|
741
892
|
KEYCLOAK_HTTP_INTERCEPTOR,
|
|
742
893
|
KEYCLOAK_CONFIG,
|
|
743
|
-
RolesGuard
|
|
894
|
+
RolesGuard,
|
|
895
|
+
BearerTokenGuard
|
|
744
896
|
]
|
|
745
897
|
};
|
|
746
898
|
}
|
|
747
899
|
};
|
|
748
900
|
KeycloakModule = __decorateClass([
|
|
749
|
-
(0,
|
|
901
|
+
(0, import_common6.Module)({})
|
|
750
902
|
], KeycloakModule);
|
|
751
903
|
// Annotate the CommonJS export names for ESM import in node:
|
|
752
904
|
0 && (module.exports = {
|
|
905
|
+
BearerTokenGuard,
|
|
753
906
|
KEYCLOAK_CLIENT,
|
|
754
907
|
KEYCLOAK_CONFIG,
|
|
755
908
|
KEYCLOAK_HTTP_INTERCEPTOR,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adatechnology/auth-keycloak",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -11,9 +11,9 @@
|
|
|
11
11
|
"dist"
|
|
12
12
|
],
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"@adatechnology/cache": "0.0.
|
|
15
|
-
"@adatechnology/http-client": "0.0.
|
|
16
|
-
"@adatechnology/logger": "0.0.
|
|
14
|
+
"@adatechnology/cache": "0.0.8",
|
|
15
|
+
"@adatechnology/http-client": "0.0.9",
|
|
16
|
+
"@adatechnology/logger": "0.0.7"
|
|
17
17
|
},
|
|
18
18
|
"peerDependencies": {
|
|
19
19
|
"@nestjs/common": "^11.0.16",
|