@nebulr-group/bridge-auth-core 0.4.0-beta.5 → 0.4.0-beta.6
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.
|
@@ -14,14 +14,28 @@ export type JwksLogger = (message: string, ...args: unknown[]) => void;
|
|
|
14
14
|
export interface JwksServiceConfig {
|
|
15
15
|
/** JWKS endpoint for user-token verification. */
|
|
16
16
|
jwksUrl: string;
|
|
17
|
-
/**
|
|
18
|
-
|
|
17
|
+
/**
|
|
18
|
+
* Token-introspection endpoint for API-token verification.
|
|
19
|
+
*
|
|
20
|
+
* API tokens are signed with the per-app HS256 secret, which a plugin never
|
|
21
|
+
* holds — so the plugin cannot verify them locally. Instead it POSTs the
|
|
22
|
+
* token here (`{ token }`) and the Bridge returns `{ active, sub, appId,
|
|
23
|
+
* tenantId, type, privileges, exp }`. This also gives instant revocation:
|
|
24
|
+
* the Bridge re-checks the backing record on every (uncached) call.
|
|
25
|
+
*/
|
|
26
|
+
introspectionUrl: string;
|
|
19
27
|
/** Expected `iss` for user tokens. */
|
|
20
28
|
issuer: string;
|
|
21
29
|
/** Expected `aud` for user tokens (typically the appId). */
|
|
22
30
|
audience: string;
|
|
23
31
|
/** How long a remote JWKS client is reused before it is re-created. @default 3600000 (1h) */
|
|
24
32
|
cacheTtlMs?: number;
|
|
33
|
+
/**
|
|
34
|
+
* How long a successful introspection result is cached, keyed by token.
|
|
35
|
+
* Trades revocation latency for fewer network calls. `0` disables caching
|
|
36
|
+
* (every request introspects → instant revocation). @default 0
|
|
37
|
+
*/
|
|
38
|
+
introspectionCacheTtlMs?: number;
|
|
25
39
|
/** Optional debug logger. @default no-op */
|
|
26
40
|
log?: JwksLogger;
|
|
27
41
|
}
|
|
@@ -37,11 +51,17 @@ export declare class TokenVerificationError extends Error {
|
|
|
37
51
|
constructor(message: string, code: string);
|
|
38
52
|
}
|
|
39
53
|
/**
|
|
40
|
-
* Framework-agnostic, Node-only
|
|
54
|
+
* Framework-agnostic, Node-only Bridge token verification.
|
|
41
55
|
*
|
|
42
|
-
* Covers
|
|
43
|
-
*
|
|
44
|
-
*
|
|
56
|
+
* Covers two paths:
|
|
57
|
+
* - **User tokens** — verified locally via remote JWKS (asymmetric PS256;
|
|
58
|
+
* issuer/audience validated). The verifier needs no secret, so offline
|
|
59
|
+
* JWKS verification is the right tool.
|
|
60
|
+
* - **API tokens** — verified via remote *introspection* (a POST to the
|
|
61
|
+
* Bridge). API tokens are signed with the per-app HS256 secret which the
|
|
62
|
+
* plugin never holds, so the secret-holder (the Bridge) is asked. This also
|
|
63
|
+
* gives instant revocation. Successful results may be cached (off by
|
|
64
|
+
* default; see `introspectionCacheTtlMs`).
|
|
45
65
|
*
|
|
46
66
|
* This is a plain class — NOT a DI provider. Framework plugins wrap it.
|
|
47
67
|
*/
|
|
@@ -49,19 +69,16 @@ export declare class JwksService {
|
|
|
49
69
|
private readonly config;
|
|
50
70
|
private jwks;
|
|
51
71
|
private jwksInitTime;
|
|
52
|
-
|
|
53
|
-
private
|
|
72
|
+
/** token → { result, expiresAt(ms) }. Only successful introspections are cached. */
|
|
73
|
+
private readonly introspectionCache;
|
|
54
74
|
private readonly cacheTtlMs;
|
|
75
|
+
private readonly introspectionCacheTtlMs;
|
|
55
76
|
private readonly log;
|
|
56
77
|
constructor(config: JwksServiceConfig);
|
|
57
78
|
/**
|
|
58
79
|
* Initialize or refresh the user-token JWKS client.
|
|
59
80
|
*/
|
|
60
81
|
private ensureJwks;
|
|
61
|
-
/**
|
|
62
|
-
* Initialize or refresh the API-token JWKS client (cached independently).
|
|
63
|
-
*/
|
|
64
|
-
private ensureApiTokenJwks;
|
|
65
82
|
/**
|
|
66
83
|
* Verify a user JWT and return its claims.
|
|
67
84
|
*
|
|
@@ -69,15 +86,31 @@ export declare class JwksService {
|
|
|
69
86
|
*/
|
|
70
87
|
verifyToken(token: string): Promise<JwtClaims>;
|
|
71
88
|
/**
|
|
72
|
-
* Verify a Bridge API token
|
|
89
|
+
* Verify a Bridge API token by introspecting it against the Bridge.
|
|
90
|
+
*
|
|
91
|
+
* Unlike user tokens, API tokens are signed with the per-app HS256 secret
|
|
92
|
+
* which this verifier does not hold — so it asks the secret-holder. The
|
|
93
|
+
* Bridge returns whether the token is active (signature valid AND backing
|
|
94
|
+
* record live: not revoked, not expired) plus its claims.
|
|
73
95
|
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
96
|
+
* The returned `{ active: false }` covers every rejection (forged, tampered,
|
|
97
|
+
* wrong type, revoked, expired) without distinguishing them — no information
|
|
98
|
+
* leak. App-scoping is then enforced here: the introspected `appId` must
|
|
99
|
+
* equal `expectedAppId`.
|
|
76
100
|
*
|
|
77
|
-
* @throws {TokenVerificationError}
|
|
78
|
-
*
|
|
101
|
+
* @throws {TokenVerificationError}
|
|
102
|
+
* - `TOKEN_INVALID` if the token is inactive or not an API token
|
|
103
|
+
* - `APP_MISMATCH` if the token belongs to a different app
|
|
104
|
+
* - `UNKNOWN_ERROR` if the introspection request itself fails
|
|
79
105
|
*/
|
|
80
106
|
verifyApiToken(token: string, expectedAppId: string): Promise<ApiTokenClaims>;
|
|
107
|
+
/**
|
|
108
|
+
* POST the token to the introspection endpoint, with optional short-lived
|
|
109
|
+
* caching of successful results (see `introspectionCacheTtlMs`).
|
|
110
|
+
*/
|
|
111
|
+
private introspect;
|
|
112
|
+
private getCachedIntrospection;
|
|
113
|
+
private cacheIntrospection;
|
|
81
114
|
/**
|
|
82
115
|
* Map a jose verification error to a stable TokenVerificationError.
|
|
83
116
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jwks-service.d.ts","sourceRoot":"","sources":["../../src/backend/jwks-service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE5D;;;GAGG;AACH,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;AAEvE;;;;;;GAMG;AACH,MAAM,WAAW,iBAAiB;IAChC,iDAAiD;IACjD,OAAO,EAAE,MAAM,CAAC;IAChB
|
|
1
|
+
{"version":3,"file":"jwks-service.d.ts","sourceRoot":"","sources":["../../src/backend/jwks-service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE5D;;;GAGG;AACH,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;AAEvE;;;;;;GAMG;AACH,MAAM,WAAW,iBAAiB;IAChC,iDAAiD;IACjD,OAAO,EAAE,MAAM,CAAC;IAChB;;;;;;;;OAQG;IACH,gBAAgB,EAAE,MAAM,CAAC;IACzB,sCAAsC;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,4DAA4D;IAC5D,QAAQ,EAAE,MAAM,CAAC;IACjB,6FAA6F;IAC7F,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,4CAA4C;IAC5C,GAAG,CAAC,EAAE,UAAU,CAAC;CAClB;AAeD;;;;;;GAMG;AACH,qBAAa,sBAAuB,SAAQ,KAAK;aAG7B,IAAI,EAAE,MAAM;gBAD5B,OAAO,EAAE,MAAM,EACC,IAAI,EAAE,MAAM;CAK/B;AAKD;;;;;;;;;;;;;;GAcG;AACH,qBAAa,WAAW;IAcV,OAAO,CAAC,QAAQ,CAAC,MAAM;IAbnC,OAAO,CAAC,IAAI,CAAsD;IAClE,OAAO,CAAC,YAAY,CAAK;IAEzB,oFAAoF;IACpF,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAG/B;IAEJ,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,uBAAuB,CAAS;IACjD,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAa;gBAEJ,MAAM,EAAE,iBAAiB;IAOtD;;OAEG;IACH,OAAO,CAAC,UAAU;IAYlB;;;;OAIG;IACG,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC;IAqBpD;;;;;;;;;;;;;;;;;OAiBG;IACG,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IA+BnF;;;OAGG;YACW,UAAU;IAwCxB,OAAO,CAAC,sBAAsB;IAe9B,OAAO,CAAC,kBAAkB;IAU1B;;OAEG;IACH,OAAO,CAAC,oBAAoB;CAqB7B"}
|
|
@@ -15,12 +15,19 @@ export class TokenVerificationError extends Error {
|
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
17
|
const DEFAULT_CACHE_TTL_MS = 60 * 60 * 1000; // 1 hour
|
|
18
|
+
const DEFAULT_INTROSPECTION_CACHE_TTL_MS = 0; // disabled → instant revocation
|
|
18
19
|
/**
|
|
19
|
-
* Framework-agnostic, Node-only
|
|
20
|
+
* Framework-agnostic, Node-only Bridge token verification.
|
|
20
21
|
*
|
|
21
|
-
* Covers
|
|
22
|
-
*
|
|
23
|
-
*
|
|
22
|
+
* Covers two paths:
|
|
23
|
+
* - **User tokens** — verified locally via remote JWKS (asymmetric PS256;
|
|
24
|
+
* issuer/audience validated). The verifier needs no secret, so offline
|
|
25
|
+
* JWKS verification is the right tool.
|
|
26
|
+
* - **API tokens** — verified via remote *introspection* (a POST to the
|
|
27
|
+
* Bridge). API tokens are signed with the per-app HS256 secret which the
|
|
28
|
+
* plugin never holds, so the secret-holder (the Bridge) is asked. This also
|
|
29
|
+
* gives instant revocation. Successful results may be cached (off by
|
|
30
|
+
* default; see `introspectionCacheTtlMs`).
|
|
24
31
|
*
|
|
25
32
|
* This is a plain class — NOT a DI provider. Framework plugins wrap it.
|
|
26
33
|
*/
|
|
@@ -28,13 +35,16 @@ export class JwksService {
|
|
|
28
35
|
config;
|
|
29
36
|
jwks = null;
|
|
30
37
|
jwksInitTime = 0;
|
|
31
|
-
|
|
32
|
-
|
|
38
|
+
/** token → { result, expiresAt(ms) }. Only successful introspections are cached. */
|
|
39
|
+
introspectionCache = new Map();
|
|
33
40
|
cacheTtlMs;
|
|
41
|
+
introspectionCacheTtlMs;
|
|
34
42
|
log;
|
|
35
43
|
constructor(config) {
|
|
36
44
|
this.config = config;
|
|
37
45
|
this.cacheTtlMs = config.cacheTtlMs ?? DEFAULT_CACHE_TTL_MS;
|
|
46
|
+
this.introspectionCacheTtlMs =
|
|
47
|
+
config.introspectionCacheTtlMs ?? DEFAULT_INTROSPECTION_CACHE_TTL_MS;
|
|
38
48
|
this.log = config.log ?? (() => { });
|
|
39
49
|
}
|
|
40
50
|
/**
|
|
@@ -49,18 +59,6 @@ export class JwksService {
|
|
|
49
59
|
}
|
|
50
60
|
return this.jwks;
|
|
51
61
|
}
|
|
52
|
-
/**
|
|
53
|
-
* Initialize or refresh the API-token JWKS client (cached independently).
|
|
54
|
-
*/
|
|
55
|
-
ensureApiTokenJwks() {
|
|
56
|
-
const now = Date.now();
|
|
57
|
-
if (!this.apiTokenJwks || now - this.apiTokenJwksInitTime > this.cacheTtlMs) {
|
|
58
|
-
this.log('Initializing API token JWKS client', { url: this.config.apiTokenJwksUrl });
|
|
59
|
-
this.apiTokenJwks = createRemoteJWKSet(new URL(this.config.apiTokenJwksUrl));
|
|
60
|
-
this.apiTokenJwksInitTime = now;
|
|
61
|
-
}
|
|
62
|
-
return this.apiTokenJwks;
|
|
63
|
-
}
|
|
64
62
|
/**
|
|
65
63
|
* Verify a user JWT and return its claims.
|
|
66
64
|
*
|
|
@@ -85,36 +83,111 @@ export class JwksService {
|
|
|
85
83
|
}
|
|
86
84
|
}
|
|
87
85
|
/**
|
|
88
|
-
* Verify a Bridge API token
|
|
86
|
+
* Verify a Bridge API token by introspecting it against the Bridge.
|
|
87
|
+
*
|
|
88
|
+
* Unlike user tokens, API tokens are signed with the per-app HS256 secret
|
|
89
|
+
* which this verifier does not hold — so it asks the secret-holder. The
|
|
90
|
+
* Bridge returns whether the token is active (signature valid AND backing
|
|
91
|
+
* record live: not revoked, not expired) plus its claims.
|
|
89
92
|
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
93
|
+
* The returned `{ active: false }` covers every rejection (forged, tampered,
|
|
94
|
+
* wrong type, revoked, expired) without distinguishing them — no information
|
|
95
|
+
* leak. App-scoping is then enforced here: the introspected `appId` must
|
|
96
|
+
* equal `expectedAppId`.
|
|
92
97
|
*
|
|
93
|
-
* @throws {TokenVerificationError}
|
|
94
|
-
*
|
|
98
|
+
* @throws {TokenVerificationError}
|
|
99
|
+
* - `TOKEN_INVALID` if the token is inactive or not an API token
|
|
100
|
+
* - `APP_MISMATCH` if the token belongs to a different app
|
|
101
|
+
* - `UNKNOWN_ERROR` if the introspection request itself fails
|
|
95
102
|
*/
|
|
96
103
|
async verifyApiToken(token, expectedAppId) {
|
|
97
|
-
const
|
|
104
|
+
const introspection = await this.introspect(token);
|
|
105
|
+
if (!introspection.active) {
|
|
106
|
+
// Bridge already collapsed forged/tampered/revoked/expired → inactive.
|
|
107
|
+
throw new TokenVerificationError('Invalid token', 'TOKEN_INVALID');
|
|
108
|
+
}
|
|
109
|
+
if (introspection.type !== 'api') {
|
|
110
|
+
throw new TokenVerificationError('Wrong token type', 'TOKEN_INVALID');
|
|
111
|
+
}
|
|
112
|
+
if (introspection.appId !== expectedAppId) {
|
|
113
|
+
throw new TokenVerificationError('Token issued for a different app', 'APP_MISMATCH');
|
|
114
|
+
}
|
|
115
|
+
this.log('API token verified via introspection', {
|
|
116
|
+
sub: introspection.sub,
|
|
117
|
+
appId: introspection.appId,
|
|
118
|
+
});
|
|
119
|
+
return {
|
|
120
|
+
sub: introspection.sub,
|
|
121
|
+
appId: introspection.appId,
|
|
122
|
+
tenantId: introspection.tenantId ?? null,
|
|
123
|
+
type: 'api',
|
|
124
|
+
privileges: introspection.privileges ?? [],
|
|
125
|
+
...(introspection.exp != null ? { exp: introspection.exp } : {}),
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* POST the token to the introspection endpoint, with optional short-lived
|
|
130
|
+
* caching of successful results (see `introspectionCacheTtlMs`).
|
|
131
|
+
*/
|
|
132
|
+
async introspect(token) {
|
|
133
|
+
const cached = this.getCachedIntrospection(token);
|
|
134
|
+
if (cached) {
|
|
135
|
+
this.log('API token introspection cache hit');
|
|
136
|
+
return cached;
|
|
137
|
+
}
|
|
138
|
+
let response;
|
|
98
139
|
try {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
if (payload['appId'] !== expectedAppId) {
|
|
104
|
-
throw new TokenVerificationError('Token issued for a different app', 'APP_MISMATCH');
|
|
105
|
-
}
|
|
106
|
-
this.log('API token verified successfully', {
|
|
107
|
-
sub: payload.sub,
|
|
108
|
-
appId: payload['appId'],
|
|
140
|
+
response = await fetch(this.config.introspectionUrl, {
|
|
141
|
+
method: 'POST',
|
|
142
|
+
headers: { 'Content-Type': 'application/json' },
|
|
143
|
+
body: JSON.stringify({ token }),
|
|
109
144
|
});
|
|
110
|
-
return payload;
|
|
111
145
|
}
|
|
112
146
|
catch (error) {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
147
|
+
this.log('API token introspection request failed', error);
|
|
148
|
+
throw new TokenVerificationError('Introspection request failed', 'UNKNOWN_ERROR');
|
|
149
|
+
}
|
|
150
|
+
if (!response.ok) {
|
|
151
|
+
this.log('API token introspection returned a non-OK status', {
|
|
152
|
+
status: response.status,
|
|
153
|
+
});
|
|
154
|
+
throw new TokenVerificationError('Introspection endpoint error', 'UNKNOWN_ERROR');
|
|
155
|
+
}
|
|
156
|
+
let body;
|
|
157
|
+
try {
|
|
158
|
+
body = (await response.json());
|
|
159
|
+
}
|
|
160
|
+
catch (error) {
|
|
161
|
+
this.log('API token introspection returned invalid JSON', error);
|
|
162
|
+
throw new TokenVerificationError('Introspection response invalid', 'UNKNOWN_ERROR');
|
|
163
|
+
}
|
|
164
|
+
if (body.active) {
|
|
165
|
+
this.cacheIntrospection(token, body);
|
|
166
|
+
}
|
|
167
|
+
return body;
|
|
168
|
+
}
|
|
169
|
+
getCachedIntrospection(token) {
|
|
170
|
+
if (this.introspectionCacheTtlMs <= 0) {
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
173
|
+
const entry = this.introspectionCache.get(token);
|
|
174
|
+
if (!entry) {
|
|
175
|
+
return null;
|
|
176
|
+
}
|
|
177
|
+
if (Date.now() >= entry.expiresAt) {
|
|
178
|
+
this.introspectionCache.delete(token);
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
181
|
+
return entry.result;
|
|
182
|
+
}
|
|
183
|
+
cacheIntrospection(token, result) {
|
|
184
|
+
if (this.introspectionCacheTtlMs <= 0) {
|
|
185
|
+
return;
|
|
117
186
|
}
|
|
187
|
+
this.introspectionCache.set(token, {
|
|
188
|
+
result,
|
|
189
|
+
expiresAt: Date.now() + this.introspectionCacheTtlMs,
|
|
190
|
+
});
|
|
118
191
|
}
|
|
119
192
|
/**
|
|
120
193
|
* Map a jose verification error to a stable TokenVerificationError.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jwks-service.js","sourceRoot":"","sources":["../../src/backend/jwks-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,SAAS,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"jwks-service.js","sourceRoot":"","sources":["../../src/backend/jwks-service.ts"],"names":[],"mappings":"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"}
|