nestjs-keycloak-auth 1.1.0 → 1.1.1

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 CHANGED
@@ -64,6 +64,7 @@ KeycloakAuthModule.register({
64
64
  policyEnforcement: PolicyEnforcementMode.PERMISSIVE, // optional
65
65
  tokenValidation: TokenValidation.ONLINE, // optional
66
66
  backchannelLogoutTtlMs: 24 * 60 * 60 * 1000, // optional, defaults to 24 hours
67
+ clockSkewSec: 5, // optional, defaults to 0; used by OFFLINE expiration checks
67
68
  });
68
69
  ```
69
70
 
@@ -100,6 +101,7 @@ export class KeycloakConfigService implements KeycloakAuthOptionsFactory {
100
101
  policyEnforcement: PolicyEnforcementMode.PERMISSIVE,
101
102
  tokenValidation: TokenValidation.ONLINE,
102
103
  backchannelLogoutTtlMs: 24 * 60 * 60 * 1000,
104
+ clockSkewSec: 5,
103
105
  };
104
106
  }
105
107
  }
@@ -348,13 +350,14 @@ Current test setup uses Jest + ts-jest and is configured to enforce 100% global
348
350
 
349
351
  ### Nest Keycloak Options
350
352
 
351
- | Option | Description | Required | Default |
352
- | ----------------- | -------------------------------------------------------------------------- | -------- | ---------- |
353
- | policyEnforcement | Sets the policy enforcement mode | no | PERMISSIVE |
354
- | tokenValidation | Sets the token validation method | no | ONLINE |
355
- | multiTenant | Sets options for [multi-tenant configuration](#multi-tenant-configuration) | no | - |
356
- | roleMerge | Sets the merge mode for `@Roles` decorator | no | OVERRIDE |
357
- | backchannelLogoutTtlMs | TTL for in-memory back-channel logout revocation entries in milliseconds | no | 86400000 |
353
+ | Option | Description | Required | Default |
354
+ | ---------------------- | ------------------------------------------------------------------------ | -------- | ---------- |
355
+ | policyEnforcement | Sets the policy enforcement mode | no | PERMISSIVE |
356
+ | tokenValidation | Sets the token validation method | no | ONLINE |
357
+ | multiTenant | Sets options for multi-tenant configuration | no | - |
358
+ | roleMerge | Sets the merge mode for `@Roles` decorator | no | OVERRIDE |
359
+ | backchannelLogoutTtlMs | TTL for in-memory back-channel logout revocation entries in milliseconds | no | 86400000 |
360
+ | clockSkewSec | Allowed clock skew for OFFLINE token expiration checks in seconds | no | 0 |
358
361
 
359
362
  ### Common Keycloak Config Fields
360
363
 
@@ -50,6 +50,11 @@ export interface NestKeycloakConfig {
50
50
  * Defaults to 24 hours.
51
51
  */
52
52
  backchannelLogoutTtlMs?: number;
53
+ /**
54
+ * Allowed clock skew for OFFLINE token expiration checks in seconds.
55
+ * Defaults to 0.
56
+ */
57
+ clockSkewSec?: number;
53
58
  }
54
59
  /**
55
60
  * Keycloak Connect options.
@@ -26,4 +26,5 @@ export declare class TokenValidationService {
26
26
  */
27
27
  validateOffline(jwt: string, realmUrl: string, clientId?: string, expectedType?: string): Promise<boolean>;
28
28
  private verifySignature;
29
+ private getClockSkewSec;
29
30
  }
@@ -123,7 +123,7 @@ let TokenValidationService = TokenValidationService_1 = class TokenValidationSer
123
123
  return false;
124
124
  }
125
125
  // Check expiry
126
- if (token.isExpired()) {
126
+ if (token.isExpired(this.getClockSkewSec())) {
127
127
  this.logger.verbose('invalid token (expired)');
128
128
  return false;
129
129
  }
@@ -200,6 +200,12 @@ let TokenValidationService = TokenValidationService_1 = class TokenValidationSer
200
200
  // crypto.verify() auto-detects key type (RSA vs EC) from the KeyObject
201
201
  return crypto.verify(hash, Buffer.from(signed), keyObj, signature);
202
202
  }
203
+ getClockSkewSec() {
204
+ const clockSkewSec = this.keycloakOpts.clockSkewSec;
205
+ return typeof clockSkewSec === 'number' && Number.isFinite(clockSkewSec) && clockSkewSec > 0
206
+ ? clockSkewSec
207
+ : 0;
208
+ }
203
209
  };
204
210
  exports.TokenValidationService = TokenValidationService;
205
211
  TokenValidationService.ALLOWED_ALGS = new Set([
@@ -49,7 +49,7 @@ export declare class KeycloakToken {
49
49
  * Check if the token is expired.
50
50
  * Matches keycloak-connect's behavior: exp=0 is considered expired.
51
51
  */
52
- isExpired(): boolean;
52
+ isExpired(clockSkewSec?: number): boolean;
53
53
  /**
54
54
  * Get the raw JWT string.
55
55
  */
@@ -92,8 +92,8 @@ class KeycloakToken {
92
92
  * Check if the token is expired.
93
93
  * Matches keycloak-connect's behavior: exp=0 is considered expired.
94
94
  */
95
- isExpired() {
96
- return this.content.exp * 1000 < Date.now();
95
+ isExpired(clockSkewSec = 0) {
96
+ return (this.content.exp + clockSkewSec) * 1000 < Date.now();
97
97
  }
98
98
  /**
99
99
  * Get the raw JWT string.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nestjs-keycloak-auth",
3
- "version": "1.1.0",
3
+ "version": "1.1.1",
4
4
  "description": "Keycloak authentication and authorization module for NestJS",
5
5
  "author": "B. Joshua Adedigba",
6
6
  "contributors": [