@iqauth/sdk 2.2.0 → 2.5.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 +134 -0
- package/dist/browser-session.d.mts +3 -3
- package/dist/browser-session.d.ts +3 -3
- package/dist/browser-session.js +89 -68
- package/dist/browser-session.mjs +2 -1
- package/dist/browser.d.mts +64 -29
- package/dist/browser.d.ts +64 -29
- package/dist/browser.js +794 -39
- package/dist/browser.mjs +44 -4
- package/dist/bundle-LUKDQYVQ.mjs +374 -0
- package/dist/chunk-3JULWS6F.mjs +106 -0
- package/dist/chunk-5T7GHBX6.mjs +1165 -0
- package/dist/{chunk-M4J6BPK7.mjs → chunk-6TDJJER7.mjs} +12 -3
- package/dist/{chunk-QZB745C2.mjs → chunk-76W5TLQQ.mjs} +264 -211
- package/dist/{chunk-D72UL5HL.mjs → chunk-BVV54LPI.mjs} +36 -4
- package/dist/chunk-LIZYFXH7.mjs +90 -0
- package/dist/chunk-MKKZULZR.mjs +241 -0
- package/dist/chunk-SL3KRS4W.mjs +54 -0
- package/dist/chunk-TKZTCPEK.mjs +232 -0
- package/dist/chunk-UKZLOHZG.mjs +83 -0
- package/dist/chunk-UNYDG2L4.mjs +209 -0
- package/dist/{chunk-MDUHPQMM.mjs → chunk-W3F4JYGP.mjs} +8 -180
- package/dist/{chunk-QEJB7WEQ.mjs → chunk-WQWBJSSS.mjs} +1 -1
- package/dist/cli/index.js +144 -36
- package/dist/cli/index.mjs +1 -1
- package/dist/{client-DXbHb2ul.d.ts → client-BNQe3AgF.d.ts} +3 -67
- package/dist/{client-Dv4v92Mj.d.mts → client-kYlJFgPv.d.mts} +3 -67
- package/dist/doctor-YYNHNMLD.mjs +198 -0
- package/dist/{express-BZmF1llh.d.mts → express-B6_1vBYZ.d.mts} +23 -2
- package/dist/{express-B4o3P8vK.d.ts → express-CHpfa7D_.d.ts} +23 -2
- package/dist/express.d.mts +77 -6
- package/dist/express.d.ts +77 -6
- package/dist/express.js +336 -74
- package/dist/express.mjs +209 -8
- package/dist/fastify.js +103 -72
- package/dist/fastify.mjs +6 -4
- package/dist/hono.js +102 -72
- package/dist/hono.mjs +5 -4
- package/dist/index.d.mts +8 -4
- package/dist/index.d.ts +8 -4
- package/dist/index.js +590 -73
- package/dist/index.mjs +30 -8
- package/dist/locales.d.mts +53 -0
- package/dist/locales.d.ts +53 -0
- package/dist/locales.js +1202 -0
- package/dist/locales.mjs +29 -0
- package/dist/mobile.d.mts +3 -3
- package/dist/mobile.d.ts +3 -3
- package/dist/mobile.js +89 -68
- package/dist/mobile.mjs +2 -1
- package/dist/next.d.mts +10 -1
- package/dist/next.d.ts +10 -1
- package/dist/next.js +101 -1618
- package/dist/next.mjs +9 -9
- package/dist/provisioningBridge-88xjOS2n.d.mts +86 -0
- package/dist/provisioningBridge-DnTfzdZK.d.ts +86 -0
- package/dist/react.d.mts +1349 -10
- package/dist/react.d.ts +1349 -10
- package/dist/react.js +2998 -569
- package/dist/react.mjs +1518 -95
- package/dist/reverify-4UEJXUS6.mjs +16 -0
- package/dist/server/handlers.d.mts +12 -1
- package/dist/server/handlers.d.ts +12 -1
- package/dist/server/handlers.js +12 -3
- package/dist/server/handlers.mjs +2 -2
- package/dist/server.d.mts +5 -4
- package/dist/server.d.ts +5 -4
- package/dist/server.js +188 -73
- package/dist/server.mjs +13 -8
- package/dist/service.d.mts +3 -3
- package/dist/service.d.ts +3 -3
- package/dist/service.js +89 -68
- package/dist/service.mjs +2 -1
- package/dist/signIn-CCY4JE5G.mjs +15 -0
- package/dist/{signIn-D_kP3v-c.d.mts → signIn-CiIBTJIh.d.mts} +232 -4
- package/dist/{signIn-BVDTIA_t.d.ts → signIn-OCr88Zf8.d.ts} +232 -4
- package/dist/test.d.mts +86 -0
- package/dist/test.d.ts +86 -0
- package/dist/test.js +289 -0
- package/dist/test.mjs +9 -0
- package/dist/tokens-DCyzzn8L.d.mts +63 -0
- package/dist/tokens-aHiGFr_E.d.ts +63 -0
- package/dist/types-6bNdxesb.d.mts +196 -0
- package/dist/types-6bNdxesb.d.ts +196 -0
- package/dist/{types-Cxl3bQHt.d.ts → types-DZAflmmq.d.mts} +6 -0
- package/dist/{types-Cxl3bQHt.d.mts → types-DZAflmmq.d.ts} +6 -0
- package/dist/webhooks.d.mts +61 -0
- package/dist/webhooks.d.ts +61 -0
- package/dist/webhooks.js +119 -0
- package/dist/webhooks.mjs +11 -0
- package/dist/ws.d.mts +73 -0
- package/dist/ws.d.ts +73 -0
- package/dist/ws.js +397 -0
- package/dist/ws.mjs +12 -0
- package/package.json +24 -3
- package/dist/doctor-XCI77BQS.mjs +0 -90
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import {
|
|
2
|
+
PRIOR_SESSION_STORAGE_KEY,
|
|
3
|
+
enterImpersonation,
|
|
4
|
+
exitImpersonation,
|
|
5
|
+
reverify,
|
|
6
|
+
withReverification
|
|
7
|
+
} from "./chunk-LIZYFXH7.mjs";
|
|
8
|
+
import "./chunk-6I6RM4MN.mjs";
|
|
9
|
+
import "./chunk-Y6FXYEAI.mjs";
|
|
10
|
+
export {
|
|
11
|
+
PRIOR_SESSION_STORAGE_KEY,
|
|
12
|
+
enterImpersonation,
|
|
13
|
+
exitImpersonation,
|
|
14
|
+
reverify,
|
|
15
|
+
withReverification
|
|
16
|
+
};
|
|
@@ -47,6 +47,11 @@ interface IQAuthHelperConfig {
|
|
|
47
47
|
accessCookieName?: string;
|
|
48
48
|
/** Override the refresh token cookie name. Defaults to `iqauth_rt`. */
|
|
49
49
|
refreshCookieName?: string;
|
|
50
|
+
/** F14 — Umbrella shorthand for `accessCookieName` / `refreshCookieName`. */
|
|
51
|
+
cookieNames?: {
|
|
52
|
+
access?: string;
|
|
53
|
+
refresh?: string;
|
|
54
|
+
};
|
|
50
55
|
/** Cookie domain (e.g. `.example.com`). Defaults to host-only. */
|
|
51
56
|
cookieDomain?: string;
|
|
52
57
|
/** Cookie sameSite policy. Defaults to `lax`. */
|
|
@@ -82,7 +87,11 @@ interface IQAuthHelperConfig {
|
|
|
82
87
|
*/
|
|
83
88
|
clearCookiesOnRefreshFailure?: "terminal-only" | "always" | "never";
|
|
84
89
|
}
|
|
85
|
-
interface ResolvedConfig extends Required<Omit<IQAuthHelperConfig, "secretKey" | "cookieDomain" | "issuer" | "fetchImpl" | "clearCookiesOnRefreshFailure">> {
|
|
90
|
+
interface ResolvedConfig extends Required<Omit<IQAuthHelperConfig, "secretKey" | "cookieDomain" | "issuer" | "fetchImpl" | "clearCookiesOnRefreshFailure" | "cookieNames">> {
|
|
91
|
+
cookieNames?: {
|
|
92
|
+
access?: string;
|
|
93
|
+
refresh?: string;
|
|
94
|
+
};
|
|
86
95
|
secretKey?: string;
|
|
87
96
|
cookieDomain?: string;
|
|
88
97
|
issuer: string;
|
|
@@ -118,6 +127,8 @@ declare function handleRefresh(config: IQAuthHelperConfig, input: {
|
|
|
118
127
|
/** POST /api/iqauth/signout — clear cookies and best-effort revoke at issuer. */
|
|
119
128
|
declare function handleSignout(config: IQAuthHelperConfig, input: {
|
|
120
129
|
accessToken?: string;
|
|
130
|
+
ssoCookieHeader?: string;
|
|
131
|
+
endSsoSession?: boolean;
|
|
121
132
|
}): Promise<HandlerResponse>;
|
|
122
133
|
|
|
123
134
|
export { type HandlerResponse, type IQAuthHelperConfig, type ResolvedConfig as ResolvedIQAuthHelperConfig, type SetCookieDirective, handleCallback, handleRefresh, handleSignout, serializeCookie };
|
|
@@ -47,6 +47,11 @@ interface IQAuthHelperConfig {
|
|
|
47
47
|
accessCookieName?: string;
|
|
48
48
|
/** Override the refresh token cookie name. Defaults to `iqauth_rt`. */
|
|
49
49
|
refreshCookieName?: string;
|
|
50
|
+
/** F14 — Umbrella shorthand for `accessCookieName` / `refreshCookieName`. */
|
|
51
|
+
cookieNames?: {
|
|
52
|
+
access?: string;
|
|
53
|
+
refresh?: string;
|
|
54
|
+
};
|
|
50
55
|
/** Cookie domain (e.g. `.example.com`). Defaults to host-only. */
|
|
51
56
|
cookieDomain?: string;
|
|
52
57
|
/** Cookie sameSite policy. Defaults to `lax`. */
|
|
@@ -82,7 +87,11 @@ interface IQAuthHelperConfig {
|
|
|
82
87
|
*/
|
|
83
88
|
clearCookiesOnRefreshFailure?: "terminal-only" | "always" | "never";
|
|
84
89
|
}
|
|
85
|
-
interface ResolvedConfig extends Required<Omit<IQAuthHelperConfig, "secretKey" | "cookieDomain" | "issuer" | "fetchImpl" | "clearCookiesOnRefreshFailure">> {
|
|
90
|
+
interface ResolvedConfig extends Required<Omit<IQAuthHelperConfig, "secretKey" | "cookieDomain" | "issuer" | "fetchImpl" | "clearCookiesOnRefreshFailure" | "cookieNames">> {
|
|
91
|
+
cookieNames?: {
|
|
92
|
+
access?: string;
|
|
93
|
+
refresh?: string;
|
|
94
|
+
};
|
|
86
95
|
secretKey?: string;
|
|
87
96
|
cookieDomain?: string;
|
|
88
97
|
issuer: string;
|
|
@@ -118,6 +127,8 @@ declare function handleRefresh(config: IQAuthHelperConfig, input: {
|
|
|
118
127
|
/** POST /api/iqauth/signout — clear cookies and best-effort revoke at issuer. */
|
|
119
128
|
declare function handleSignout(config: IQAuthHelperConfig, input: {
|
|
120
129
|
accessToken?: string;
|
|
130
|
+
ssoCookieHeader?: string;
|
|
131
|
+
endSsoSession?: boolean;
|
|
121
132
|
}): Promise<HandlerResponse>;
|
|
122
133
|
|
|
123
134
|
export { type HandlerResponse, type IQAuthHelperConfig, type ResolvedConfig as ResolvedIQAuthHelperConfig, type SetCookieDirective, handleCallback, handleRefresh, handleSignout, serializeCookie };
|
package/dist/server/handlers.js
CHANGED
|
@@ -96,7 +96,7 @@ function assertPublishableKey(raw, opts) {
|
|
|
96
96
|
if (!isValidIssuerUrl(decoded.iss)) {
|
|
97
97
|
throw new IQAuthError(
|
|
98
98
|
"CONFIG_INVALID",
|
|
99
|
-
`${ctx}IQAuth publishable key encodes an invalid issuer (iss=${JSON.stringify(decoded.iss)}). Expected a fully-qualified URL like "https://auth.example.com" (scheme required). Regenerate the key from the IQAuth admin console
|
|
99
|
+
`${ctx}IQAuth publishable key encodes an invalid issuer (iss=${JSON.stringify(decoded.iss)}). Expected a fully-qualified URL like "https://auth.example.com" (scheme required). Regenerate the key from the IQAuth admin console \u2014 the new key will encode a valid issuer URL.`
|
|
100
100
|
);
|
|
101
101
|
}
|
|
102
102
|
return { mode: shapeMatch[1], iss: decoded.iss, appId: decoded.appId, tenantId: decoded.tenantId, kid: decoded.kid, raw };
|
|
@@ -133,8 +133,8 @@ function resolve(config) {
|
|
|
133
133
|
publishableKey: config.publishableKey,
|
|
134
134
|
secretKey: config.secretKey,
|
|
135
135
|
issuer: (config.issuer ?? inferredIssuer).replace(/\/+$/, ""),
|
|
136
|
-
accessCookieName: config.accessCookieName ?? "iqauth_at",
|
|
137
|
-
refreshCookieName: config.refreshCookieName ?? "iqauth_rt",
|
|
136
|
+
accessCookieName: config.accessCookieName ?? config.cookieNames?.access ?? "iqauth_at",
|
|
137
|
+
refreshCookieName: config.refreshCookieName ?? config.cookieNames?.refresh ?? "iqauth_rt",
|
|
138
138
|
cookieDomain: config.cookieDomain,
|
|
139
139
|
sameSite: config.sameSite ?? "lax",
|
|
140
140
|
secure: config.secure ?? true,
|
|
@@ -298,6 +298,15 @@ async function handleSignout(config, input) {
|
|
|
298
298
|
} catch {
|
|
299
299
|
}
|
|
300
300
|
}
|
|
301
|
+
if (input.endSsoSession !== false && input.ssoCookieHeader) {
|
|
302
|
+
try {
|
|
303
|
+
await cfg.fetchImpl(`${cfg.issuer}/oidc/sso-logout`, {
|
|
304
|
+
method: "POST",
|
|
305
|
+
headers: { Cookie: input.ssoCookieHeader }
|
|
306
|
+
});
|
|
307
|
+
} catch {
|
|
308
|
+
}
|
|
309
|
+
}
|
|
301
310
|
return {
|
|
302
311
|
status: 200,
|
|
303
312
|
body: { success: true, data: { signedOut: true } },
|
package/dist/server/handlers.mjs
CHANGED
|
@@ -3,8 +3,8 @@ import {
|
|
|
3
3
|
handleRefresh,
|
|
4
4
|
handleSignout,
|
|
5
5
|
serializeCookie
|
|
6
|
-
} from "../chunk-
|
|
7
|
-
import "../chunk-
|
|
6
|
+
} from "../chunk-6TDJJER7.mjs";
|
|
7
|
+
import "../chunk-WQWBJSSS.mjs";
|
|
8
8
|
import "../chunk-6I6RM4MN.mjs";
|
|
9
9
|
import "../chunk-Y6FXYEAI.mjs";
|
|
10
10
|
export {
|
package/dist/server.d.mts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { b as IQAuthTokenClientConfig, N as ExpressMiddlewareOptions, Q as IQAuthRequestLike, R as IQAuthResponseLike, V as IQAuthNextFunction } from './types-
|
|
2
|
-
import { I as IQAuthClient } from './client-
|
|
1
|
+
import { b as IQAuthTokenClientConfig, N as ExpressMiddlewareOptions, Q as IQAuthRequestLike, R as IQAuthResponseLike, V as IQAuthNextFunction } from './types-DZAflmmq.mjs';
|
|
2
|
+
import { I as IQAuthClient } from './client-kYlJFgPv.mjs';
|
|
3
3
|
export { E as ErrorCodes, I as IQAuthError } from './errors-CDdl24MP.mjs';
|
|
4
|
-
export { C as CookieAwareMiddlewareOptions, D as DEFAULT_ACCESS_COOKIE, a as DEFAULT_REFRESH_COOKIE, i as iqAuthMiddleware } from './express-
|
|
4
|
+
export { C as CookieAwareMiddlewareOptions, D as DEFAULT_ACCESS_COOKIE, a as DEFAULT_REFRESH_COOKIE, i as iqAuthMiddleware } from './express-B6_1vBYZ.mjs';
|
|
5
5
|
export { HandlerResponse, IQAuthHelperConfig, SetCookieDirective, handleCallback, handleRefresh, handleSignout, serializeCookie } from './server/handlers.mjs';
|
|
6
|
-
|
|
6
|
+
export { P as ProvisioningBridge, a as ProvisioningBridgeOptions, d as ProvisioningContext, b as ProvisioningStorage, c as createProvisioningBridge } from './provisioningBridge-88xjOS2n.mjs';
|
|
7
|
+
import './tokens-DCyzzn8L.mjs';
|
|
7
8
|
|
|
8
9
|
declare class ServerIQAuthClient extends IQAuthClient {
|
|
9
10
|
constructor(config: IQAuthTokenClientConfig);
|
package/dist/server.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { b as IQAuthTokenClientConfig, N as ExpressMiddlewareOptions, Q as IQAuthRequestLike, R as IQAuthResponseLike, V as IQAuthNextFunction } from './types-
|
|
2
|
-
import { I as IQAuthClient } from './client-
|
|
1
|
+
import { b as IQAuthTokenClientConfig, N as ExpressMiddlewareOptions, Q as IQAuthRequestLike, R as IQAuthResponseLike, V as IQAuthNextFunction } from './types-DZAflmmq.js';
|
|
2
|
+
import { I as IQAuthClient } from './client-BNQe3AgF.js';
|
|
3
3
|
export { E as ErrorCodes, I as IQAuthError } from './errors-CDdl24MP.js';
|
|
4
|
-
export { C as CookieAwareMiddlewareOptions, D as DEFAULT_ACCESS_COOKIE, a as DEFAULT_REFRESH_COOKIE, i as iqAuthMiddleware } from './express-
|
|
4
|
+
export { C as CookieAwareMiddlewareOptions, D as DEFAULT_ACCESS_COOKIE, a as DEFAULT_REFRESH_COOKIE, i as iqAuthMiddleware } from './express-CHpfa7D_.js';
|
|
5
5
|
export { HandlerResponse, IQAuthHelperConfig, SetCookieDirective, handleCallback, handleRefresh, handleSignout, serializeCookie } from './server/handlers.js';
|
|
6
|
-
|
|
6
|
+
export { P as ProvisioningBridge, a as ProvisioningBridgeOptions, d as ProvisioningContext, b as ProvisioningStorage, c as createProvisioningBridge } from './provisioningBridge-DnTfzdZK.js';
|
|
7
|
+
import './tokens-aHiGFr_E.js';
|
|
7
8
|
|
|
8
9
|
declare class ServerIQAuthClient extends IQAuthClient {
|
|
9
10
|
constructor(config: IQAuthTokenClientConfig);
|
package/dist/server.js
CHANGED
|
@@ -36,6 +36,7 @@ __export(server_exports, {
|
|
|
36
36
|
IQAuthClient: () => IQAuthClient,
|
|
37
37
|
IQAuthError: () => IQAuthError,
|
|
38
38
|
ServerIQAuthClient: () => ServerIQAuthClient,
|
|
39
|
+
createProvisioningBridge: () => createProvisioningBridge,
|
|
39
40
|
createServerClient: () => createServerClient,
|
|
40
41
|
handleCallback: () => handleCallback,
|
|
41
42
|
handleRefresh: () => handleRefresh,
|
|
@@ -453,8 +454,7 @@ function parseMfaResponse(data, browserSessionMode) {
|
|
|
453
454
|
}
|
|
454
455
|
|
|
455
456
|
// src/modules/tokens.ts
|
|
456
|
-
var
|
|
457
|
-
var import_jsonwebtoken = __toESM(require("jsonwebtoken"));
|
|
457
|
+
var import_jose = require("jose");
|
|
458
458
|
var JWKS_CACHE_TTL_MS = 60 * 60 * 1e3;
|
|
459
459
|
var DEFAULT_TOKEN_ISSUER = [
|
|
460
460
|
"https://auth.dispositioniq.com",
|
|
@@ -467,6 +467,24 @@ var DEFAULT_TOKEN_AUDIENCE = [
|
|
|
467
467
|
"iqvalidate"
|
|
468
468
|
];
|
|
469
469
|
var DEFAULT_CLOCK_TOLERANCE_SECONDS = 30;
|
|
470
|
+
function decodeProtectedHeader(token) {
|
|
471
|
+
const parts = token.split(".");
|
|
472
|
+
if (parts.length < 2) return null;
|
|
473
|
+
try {
|
|
474
|
+
const padded = parts[0] + "=".repeat((4 - parts[0].length % 4) % 4);
|
|
475
|
+
const b64 = padded.replace(/-/g, "+").replace(/_/g, "/");
|
|
476
|
+
let json;
|
|
477
|
+
if (typeof atob === "function") {
|
|
478
|
+
json = atob(b64);
|
|
479
|
+
} else {
|
|
480
|
+
const { Buffer: Buffer2 } = require("buffer");
|
|
481
|
+
json = Buffer2.from(b64, "base64").toString("utf8");
|
|
482
|
+
}
|
|
483
|
+
return JSON.parse(json);
|
|
484
|
+
} catch {
|
|
485
|
+
return null;
|
|
486
|
+
}
|
|
487
|
+
}
|
|
470
488
|
var TokensModule = class {
|
|
471
489
|
constructor(baseUrl, options = {}) {
|
|
472
490
|
this.jwksCache = null;
|
|
@@ -477,49 +495,49 @@ var TokensModule = class {
|
|
|
477
495
|
this.defaultClockTolerance = options.clockTolerance ?? DEFAULT_CLOCK_TOLERANCE_SECONDS;
|
|
478
496
|
}
|
|
479
497
|
/**
|
|
480
|
-
* Verify a JWT access token using RS256 via JWKS from
|
|
481
|
-
*
|
|
482
|
-
*
|
|
483
|
-
*
|
|
484
|
-
* clock tolerance default to client config but can be overridden per call.
|
|
498
|
+
* Verify a JWT access token using RS256/ES256 via JWKS from
|
|
499
|
+
* `/.well-known/jwks.json`. Backed by `jose` (Web Crypto) so it runs on
|
|
500
|
+
* Node, browser, and edge runtimes alike — no `node:crypto` dependency.
|
|
501
|
+
* Caches JWKS for 1 hour and refetches once on unknown `kid`.
|
|
485
502
|
*/
|
|
486
503
|
async verify(token, options = {}) {
|
|
487
|
-
const
|
|
488
|
-
if (!
|
|
504
|
+
const header = decodeProtectedHeader(token);
|
|
505
|
+
if (!header) {
|
|
489
506
|
throw new IQAuthError("TOKEN_INVALID", "Unable to decode token");
|
|
490
507
|
}
|
|
491
|
-
const kid =
|
|
508
|
+
const kid = header.kid;
|
|
492
509
|
if (!kid) {
|
|
493
510
|
throw new IQAuthError("TOKEN_INVALID", "Token missing kid header");
|
|
494
511
|
}
|
|
495
|
-
let
|
|
496
|
-
if (!
|
|
497
|
-
|
|
498
|
-
|
|
512
|
+
let cache = await this.ensureCache();
|
|
513
|
+
if (!cache.byKid.has(kid)) {
|
|
514
|
+
this.jwksCache = null;
|
|
515
|
+
cache = await this.ensureCache();
|
|
499
516
|
}
|
|
500
|
-
if (!
|
|
517
|
+
if (!cache.byKid.has(kid)) {
|
|
501
518
|
throw new IQAuthError("TOKEN_INVALID", `Unknown key ID: ${kid}`);
|
|
502
519
|
}
|
|
503
520
|
const issuer = options.issuer ?? this.defaultIssuer;
|
|
504
521
|
const audience = options.audience ?? this.defaultAudience;
|
|
505
522
|
const clockTolerance = options.clockTolerance ?? this.defaultClockTolerance;
|
|
506
|
-
const algorithms = options.algorithms ?? ["RS256"];
|
|
523
|
+
const algorithms = options.algorithms ?? ["RS256", "ES256"];
|
|
524
|
+
const verifyOptions = {
|
|
525
|
+
algorithms,
|
|
526
|
+
clockTolerance,
|
|
527
|
+
issuer,
|
|
528
|
+
audience
|
|
529
|
+
};
|
|
507
530
|
try {
|
|
508
|
-
const
|
|
509
|
-
|
|
510
|
-
clockTolerance,
|
|
511
|
-
// The jsonwebtoken types insist on tuple types for arrays; runtime
|
|
512
|
-
// accepts plain string[] so we cast to satisfy the compiler.
|
|
513
|
-
issuer,
|
|
514
|
-
audience
|
|
515
|
-
};
|
|
516
|
-
const verified = import_jsonwebtoken.default.verify(token, publicKey, verifyOptions);
|
|
517
|
-
return verified;
|
|
531
|
+
const { payload } = await (0, import_jose.jwtVerify)(token, cache.verifier, verifyOptions);
|
|
532
|
+
return payload;
|
|
518
533
|
} catch (err) {
|
|
534
|
+
if (err instanceof import_jose.errors.JWTExpired) {
|
|
535
|
+
throw new IQAuthError("TOKEN_EXPIRED", "Token has expired");
|
|
536
|
+
}
|
|
537
|
+
if (err instanceof import_jose.errors.JOSEError) {
|
|
538
|
+
throw new IQAuthError("TOKEN_INVALID", err.message);
|
|
539
|
+
}
|
|
519
540
|
if (err instanceof Error) {
|
|
520
|
-
if (err.name === "TokenExpiredError") {
|
|
521
|
-
throw new IQAuthError("TOKEN_EXPIRED", "Token has expired");
|
|
522
|
-
}
|
|
523
541
|
throw new IQAuthError("TOKEN_INVALID", err.message);
|
|
524
542
|
}
|
|
525
543
|
throw new IQAuthError("TOKEN_INVALID", "Token verification failed");
|
|
@@ -527,29 +545,40 @@ var TokensModule = class {
|
|
|
527
545
|
}
|
|
528
546
|
/**
|
|
529
547
|
* Decode a JWT without verification. Returns null if malformed.
|
|
530
|
-
*
|
|
531
|
-
* @remarks Local decode only — no network call
|
|
532
548
|
*/
|
|
533
549
|
decode(token) {
|
|
534
|
-
|
|
535
|
-
|
|
550
|
+
try {
|
|
551
|
+
const parts = token.split(".");
|
|
552
|
+
if (parts.length < 2) return null;
|
|
553
|
+
const payload = parts[1];
|
|
554
|
+
const padded = payload + "=".repeat((4 - payload.length % 4) % 4);
|
|
555
|
+
const b64 = padded.replace(/-/g, "+").replace(/_/g, "/");
|
|
556
|
+
let json;
|
|
557
|
+
if (typeof atob === "function") {
|
|
558
|
+
json = atob(b64);
|
|
559
|
+
} else {
|
|
560
|
+
const { Buffer: Buffer2 } = require("buffer");
|
|
561
|
+
json = Buffer2.from(b64, "base64").toString("utf8");
|
|
562
|
+
}
|
|
563
|
+
try {
|
|
564
|
+
json = decodeURIComponent(escape(json));
|
|
565
|
+
} catch {
|
|
566
|
+
}
|
|
567
|
+
const claims = JSON.parse(json);
|
|
568
|
+
if (!claims || typeof claims !== "object") return null;
|
|
569
|
+
return claims;
|
|
570
|
+
} catch {
|
|
571
|
+
return null;
|
|
572
|
+
}
|
|
536
573
|
}
|
|
537
|
-
/**
|
|
538
|
-
* Check if a token is expired based on the `exp` claim.
|
|
539
|
-
*
|
|
540
|
-
* @remarks Local check only — no network call
|
|
541
|
-
*/
|
|
574
|
+
/** Check if a token is expired based on the `exp` claim. */
|
|
542
575
|
isExpired(token) {
|
|
543
576
|
const claims = this.decode(token);
|
|
544
577
|
if (!claims?.exp) return true;
|
|
545
578
|
const now = Math.floor(Date.now() / 1e3);
|
|
546
579
|
return claims.exp <= now;
|
|
547
580
|
}
|
|
548
|
-
/**
|
|
549
|
-
* Get the claims from a token without verification.
|
|
550
|
-
*
|
|
551
|
-
* @remarks Local decode only — no network call
|
|
552
|
-
*/
|
|
581
|
+
/** Get the claims from a token without verification. */
|
|
553
582
|
getClaims(token) {
|
|
554
583
|
const claims = this.decode(token);
|
|
555
584
|
if (!claims) {
|
|
@@ -557,11 +586,15 @@ var TokensModule = class {
|
|
|
557
586
|
}
|
|
558
587
|
return claims;
|
|
559
588
|
}
|
|
560
|
-
async
|
|
561
|
-
if (
|
|
562
|
-
|
|
589
|
+
async ensureCache() {
|
|
590
|
+
if (this.jwksCache && Date.now() - this.jwksCache.fetchedAt <= JWKS_CACHE_TTL_MS) {
|
|
591
|
+
return this.jwksCache;
|
|
592
|
+
}
|
|
593
|
+
await this.refreshJwks();
|
|
594
|
+
if (!this.jwksCache) {
|
|
595
|
+
throw new IQAuthError("INTERNAL_ERROR", "JWKS cache unavailable after refresh");
|
|
563
596
|
}
|
|
564
|
-
return this.jwksCache
|
|
597
|
+
return this.jwksCache;
|
|
565
598
|
}
|
|
566
599
|
async refreshJwks() {
|
|
567
600
|
if (this.inFlightRefresh) {
|
|
@@ -588,35 +621,24 @@ var TokensModule = class {
|
|
|
588
621
|
"Malformed JWKS response: expected { keys: [...] }"
|
|
589
622
|
);
|
|
590
623
|
}
|
|
591
|
-
const
|
|
624
|
+
const byKid = /* @__PURE__ */ new Set();
|
|
592
625
|
for (const key of jwks.keys) {
|
|
593
|
-
if (!key || typeof key.kid !== "string" || typeof key.n !== "string" || typeof key.e !== "string") {
|
|
626
|
+
if (!key || typeof key.kid !== "string" || typeof key.n !== "string" && typeof key.x !== "string" || key.kty === "RSA" && (typeof key.n !== "string" || typeof key.e !== "string")) {
|
|
594
627
|
throw new IQAuthError(
|
|
595
628
|
"INTERNAL_ERROR",
|
|
596
629
|
"Malformed JWKS response: key missing required fields"
|
|
597
630
|
);
|
|
598
631
|
}
|
|
599
|
-
|
|
600
|
-
keys.set(key.kid, pem);
|
|
632
|
+
byKid.add(key.kid);
|
|
601
633
|
}
|
|
602
|
-
|
|
634
|
+
const verifier = (0, import_jose.createLocalJWKSet)({ keys: jwks.keys });
|
|
635
|
+
this.jwksCache = { raw: jwks.keys, byKid, verifier, fetchedAt: Date.now() };
|
|
603
636
|
} finally {
|
|
604
637
|
this.inFlightRefresh = null;
|
|
605
638
|
}
|
|
606
639
|
})();
|
|
607
640
|
return this.inFlightRefresh;
|
|
608
641
|
}
|
|
609
|
-
jwkToPem(jwk) {
|
|
610
|
-
const keyObject = import_crypto.default.createPublicKey({
|
|
611
|
-
key: {
|
|
612
|
-
kty: jwk.kty,
|
|
613
|
-
n: jwk.n,
|
|
614
|
-
e: jwk.e
|
|
615
|
-
},
|
|
616
|
-
format: "jwk"
|
|
617
|
-
});
|
|
618
|
-
return keyObject.export({ type: "spki", format: "pem" });
|
|
619
|
-
}
|
|
620
642
|
/** @internal Exposed for testing — clears JWKS cache */
|
|
621
643
|
clearCache() {
|
|
622
644
|
this.jwksCache = null;
|
|
@@ -824,7 +846,7 @@ var PermissionsModule = class {
|
|
|
824
846
|
};
|
|
825
847
|
|
|
826
848
|
// src/modules/oidc.ts
|
|
827
|
-
var
|
|
849
|
+
var import_crypto = __toESM(require("crypto"));
|
|
828
850
|
var InMemoryOidcStateStore = class {
|
|
829
851
|
constructor() {
|
|
830
852
|
this.map = /* @__PURE__ */ new Map();
|
|
@@ -905,12 +927,12 @@ var OidcModule = class {
|
|
|
905
927
|
* ready to redirect the user to.
|
|
906
928
|
*/
|
|
907
929
|
async createAuthRequest(params) {
|
|
908
|
-
const codeVerifier = base64UrlEncode(
|
|
930
|
+
const codeVerifier = base64UrlEncode(import_crypto.default.randomBytes(32));
|
|
909
931
|
const codeChallenge = base64UrlEncode(
|
|
910
|
-
|
|
932
|
+
import_crypto.default.createHash("sha256").update(codeVerifier).digest()
|
|
911
933
|
);
|
|
912
|
-
const state = base64UrlEncode(
|
|
913
|
-
const nonce = base64UrlEncode(
|
|
934
|
+
const state = base64UrlEncode(import_crypto.default.randomBytes(16));
|
|
935
|
+
const nonce = base64UrlEncode(import_crypto.default.randomBytes(16));
|
|
914
936
|
await this.stateStore.set(state, {
|
|
915
937
|
codeVerifier,
|
|
916
938
|
state,
|
|
@@ -1858,7 +1880,7 @@ function assertPublishableKey(raw, opts) {
|
|
|
1858
1880
|
if (!isValidIssuerUrl(decoded.iss)) {
|
|
1859
1881
|
throw new IQAuthError(
|
|
1860
1882
|
"CONFIG_INVALID",
|
|
1861
|
-
`${ctx}IQAuth publishable key encodes an invalid issuer (iss=${JSON.stringify(decoded.iss)}). Expected a fully-qualified URL like "https://auth.example.com" (scheme required). Regenerate the key from the IQAuth admin console
|
|
1883
|
+
`${ctx}IQAuth publishable key encodes an invalid issuer (iss=${JSON.stringify(decoded.iss)}). Expected a fully-qualified URL like "https://auth.example.com" (scheme required). Regenerate the key from the IQAuth admin console \u2014 the new key will encode a valid issuer URL.`
|
|
1862
1884
|
);
|
|
1863
1885
|
}
|
|
1864
1886
|
return { mode: shapeMatch[1], iss: decoded.iss, appId: decoded.appId, tenantId: decoded.tenantId, kid: decoded.kid, raw };
|
|
@@ -1904,6 +1926,22 @@ function readCookie(req, name) {
|
|
|
1904
1926
|
}
|
|
1905
1927
|
return void 0;
|
|
1906
1928
|
}
|
|
1929
|
+
function compileMatcher(pat) {
|
|
1930
|
+
if (pat instanceof RegExp) return (p) => pat.test(p);
|
|
1931
|
+
const re = new RegExp(
|
|
1932
|
+
"^" + pat.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, "::DOUBLE::").replace(/\*/g, "[^/]*").replace(/::DOUBLE::/g, ".*") + "$"
|
|
1933
|
+
);
|
|
1934
|
+
return (p) => re.test(p);
|
|
1935
|
+
}
|
|
1936
|
+
function compileMatchers(pats) {
|
|
1937
|
+
return (pats ?? []).map(compileMatcher);
|
|
1938
|
+
}
|
|
1939
|
+
function pathOf(req) {
|
|
1940
|
+
const r = req;
|
|
1941
|
+
const raw = r.path || r.originalUrl || r.url || "/";
|
|
1942
|
+
const q = raw.indexOf("?");
|
|
1943
|
+
return q >= 0 ? raw.slice(0, q) : raw;
|
|
1944
|
+
}
|
|
1907
1945
|
function clientFromPublishableKey(opts) {
|
|
1908
1946
|
const parsed = assertPublishableKey(opts.publishableKey, { context: "iqAuthMiddleware" });
|
|
1909
1947
|
const issuer = (opts.issuer ?? (parsed.iss.startsWith("http") ? parsed.iss : `https://${parsed.iss}`)).replace(/\/+$/, "");
|
|
@@ -1931,10 +1969,26 @@ function iqAuthMiddleware(clientOrOptions, options = {}) {
|
|
|
1931
1969
|
onUnauthorized,
|
|
1932
1970
|
onForbidden,
|
|
1933
1971
|
onError,
|
|
1934
|
-
|
|
1935
|
-
|
|
1972
|
+
cookieAware = true,
|
|
1973
|
+
cookieNames,
|
|
1974
|
+
protect,
|
|
1975
|
+
publicRoutes
|
|
1936
1976
|
} = resolvedOptions;
|
|
1977
|
+
const accessCookieName = resolvedOptions.accessCookieName ?? cookieNames?.access ?? DEFAULT_ACCESS_COOKIE;
|
|
1978
|
+
const protectMatchers = compileMatchers(protect);
|
|
1979
|
+
const publicMatchers = compileMatchers(publicRoutes);
|
|
1980
|
+
const hasProtect = protectMatchers.length > 0;
|
|
1981
|
+
const hasPublic = publicMatchers.length > 0;
|
|
1937
1982
|
return async (req, res, next) => {
|
|
1983
|
+
if (hasProtect || hasPublic) {
|
|
1984
|
+
const path = pathOf(req);
|
|
1985
|
+
if (hasPublic && publicMatchers.some((m) => m(path))) {
|
|
1986
|
+
return next();
|
|
1987
|
+
}
|
|
1988
|
+
if (hasProtect && !protectMatchers.some((m) => m(path))) {
|
|
1989
|
+
return next();
|
|
1990
|
+
}
|
|
1991
|
+
}
|
|
1938
1992
|
let token;
|
|
1939
1993
|
const authHeader = getAuthorizationHeader(req);
|
|
1940
1994
|
if (authHeader && authHeader.startsWith("Bearer ")) {
|
|
@@ -2053,8 +2107,8 @@ function resolve(config) {
|
|
|
2053
2107
|
publishableKey: config.publishableKey,
|
|
2054
2108
|
secretKey: config.secretKey,
|
|
2055
2109
|
issuer: (config.issuer ?? inferredIssuer).replace(/\/+$/, ""),
|
|
2056
|
-
accessCookieName: config.accessCookieName ?? "iqauth_at",
|
|
2057
|
-
refreshCookieName: config.refreshCookieName ?? "iqauth_rt",
|
|
2110
|
+
accessCookieName: config.accessCookieName ?? config.cookieNames?.access ?? "iqauth_at",
|
|
2111
|
+
refreshCookieName: config.refreshCookieName ?? config.cookieNames?.refresh ?? "iqauth_rt",
|
|
2058
2112
|
cookieDomain: config.cookieDomain,
|
|
2059
2113
|
sameSite: config.sameSite ?? "lax",
|
|
2060
2114
|
secure: config.secure ?? true,
|
|
@@ -2218,6 +2272,15 @@ async function handleSignout(config, input) {
|
|
|
2218
2272
|
} catch {
|
|
2219
2273
|
}
|
|
2220
2274
|
}
|
|
2275
|
+
if (input.endSsoSession !== false && input.ssoCookieHeader) {
|
|
2276
|
+
try {
|
|
2277
|
+
await cfg.fetchImpl(`${cfg.issuer}/oidc/sso-logout`, {
|
|
2278
|
+
method: "POST",
|
|
2279
|
+
headers: { Cookie: input.ssoCookieHeader }
|
|
2280
|
+
});
|
|
2281
|
+
} catch {
|
|
2282
|
+
}
|
|
2283
|
+
}
|
|
2221
2284
|
return {
|
|
2222
2285
|
status: 200,
|
|
2223
2286
|
body: { success: true, data: { signedOut: true } },
|
|
@@ -2225,6 +2288,57 @@ async function handleSignout(config, input) {
|
|
|
2225
2288
|
};
|
|
2226
2289
|
}
|
|
2227
2290
|
|
|
2291
|
+
// src/server/provisioningBridge.ts
|
|
2292
|
+
function defaultIsUniqueViolation(err) {
|
|
2293
|
+
if (!err || typeof err !== "object") return false;
|
|
2294
|
+
const e = err;
|
|
2295
|
+
if (e.code === "23505") return true;
|
|
2296
|
+
if (typeof e.code === "string" && e.code.startsWith("SQLITE_CONSTRAINT")) return true;
|
|
2297
|
+
if (typeof e.message === "string" && /unique constraint|duplicate key/i.test(e.message)) return true;
|
|
2298
|
+
return false;
|
|
2299
|
+
}
|
|
2300
|
+
function createProvisioningBridge(options) {
|
|
2301
|
+
const { storage } = options;
|
|
2302
|
+
const isUniqueViolation = options.isUniqueViolation ?? defaultIsUniqueViolation;
|
|
2303
|
+
const roleOf = (claims) => {
|
|
2304
|
+
try {
|
|
2305
|
+
return options.roleMapper?.(claims) ?? null;
|
|
2306
|
+
} catch {
|
|
2307
|
+
return null;
|
|
2308
|
+
}
|
|
2309
|
+
};
|
|
2310
|
+
const ensureUser = async (claims) => {
|
|
2311
|
+
if (!claims?.sub) {
|
|
2312
|
+
throw new Error("createProvisioningBridge: claims.sub is required");
|
|
2313
|
+
}
|
|
2314
|
+
const byId = await storage.findByIqAuthUserId(claims.sub);
|
|
2315
|
+
if (byId) return { user: byId, claims, created: false, adopted: false };
|
|
2316
|
+
if (claims.email) {
|
|
2317
|
+
const byEmail = await storage.findByEmail(claims.email);
|
|
2318
|
+
if (byEmail) {
|
|
2319
|
+
if (storage.adoptByEmail) {
|
|
2320
|
+
const adopted = await storage.adoptByEmail(byEmail, claims, roleOf(claims));
|
|
2321
|
+
return { user: adopted, claims, created: false, adopted: true };
|
|
2322
|
+
}
|
|
2323
|
+
}
|
|
2324
|
+
}
|
|
2325
|
+
try {
|
|
2326
|
+
const created = await storage.insertFromClaims(claims, roleOf(claims));
|
|
2327
|
+
return { user: created, claims, created: true, adopted: false };
|
|
2328
|
+
} catch (err) {
|
|
2329
|
+
if (!isUniqueViolation(err)) throw err;
|
|
2330
|
+
const after = await storage.findByIqAuthUserId(claims.sub);
|
|
2331
|
+
if (after) return { user: after, claims, created: false, adopted: false };
|
|
2332
|
+
if (claims.email) {
|
|
2333
|
+
const byEmail = await storage.findByEmail(claims.email);
|
|
2334
|
+
if (byEmail) return { user: byEmail, claims, created: false, adopted: true };
|
|
2335
|
+
}
|
|
2336
|
+
throw err;
|
|
2337
|
+
}
|
|
2338
|
+
};
|
|
2339
|
+
return { ensureUser };
|
|
2340
|
+
}
|
|
2341
|
+
|
|
2228
2342
|
// src/server.ts
|
|
2229
2343
|
var ServerIQAuthClient = class extends IQAuthClient {
|
|
2230
2344
|
constructor(config) {
|
|
@@ -2245,6 +2359,7 @@ function createServerClient(config) {
|
|
|
2245
2359
|
IQAuthClient,
|
|
2246
2360
|
IQAuthError,
|
|
2247
2361
|
ServerIQAuthClient,
|
|
2362
|
+
createProvisioningBridge,
|
|
2248
2363
|
createServerClient,
|
|
2249
2364
|
handleCallback,
|
|
2250
2365
|
handleRefresh,
|
package/dist/server.mjs
CHANGED
|
@@ -1,18 +1,22 @@
|
|
|
1
|
-
import {
|
|
2
|
-
DEFAULT_ACCESS_COOKIE,
|
|
3
|
-
DEFAULT_REFRESH_COOKIE,
|
|
4
|
-
iqAuthMiddleware
|
|
5
|
-
} from "./chunk-D72UL5HL.mjs";
|
|
6
1
|
import {
|
|
7
2
|
handleCallback,
|
|
8
3
|
handleRefresh,
|
|
9
4
|
handleSignout,
|
|
10
5
|
serializeCookie
|
|
11
|
-
} from "./chunk-
|
|
12
|
-
import
|
|
6
|
+
} from "./chunk-6TDJJER7.mjs";
|
|
7
|
+
import {
|
|
8
|
+
createProvisioningBridge
|
|
9
|
+
} from "./chunk-SL3KRS4W.mjs";
|
|
10
|
+
import {
|
|
11
|
+
DEFAULT_ACCESS_COOKIE,
|
|
12
|
+
DEFAULT_REFRESH_COOKIE,
|
|
13
|
+
iqAuthMiddleware
|
|
14
|
+
} from "./chunk-BVV54LPI.mjs";
|
|
15
|
+
import "./chunk-WQWBJSSS.mjs";
|
|
13
16
|
import {
|
|
14
17
|
IQAuthClient
|
|
15
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-W3F4JYGP.mjs";
|
|
19
|
+
import "./chunk-UNYDG2L4.mjs";
|
|
16
20
|
import {
|
|
17
21
|
ErrorCodes,
|
|
18
22
|
IQAuthError
|
|
@@ -38,6 +42,7 @@ export {
|
|
|
38
42
|
IQAuthClient,
|
|
39
43
|
IQAuthError,
|
|
40
44
|
ServerIQAuthClient,
|
|
45
|
+
createProvisioningBridge,
|
|
41
46
|
createServerClient,
|
|
42
47
|
handleCallback,
|
|
43
48
|
handleRefresh,
|
package/dist/service.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { I as IQAuthClient } from './client-
|
|
2
|
-
import { b as IQAuthTokenClientConfig } from './types-
|
|
1
|
+
import { I as IQAuthClient } from './client-kYlJFgPv.mjs';
|
|
2
|
+
import { b as IQAuthTokenClientConfig } from './types-DZAflmmq.mjs';
|
|
3
3
|
export { E as ErrorCodes, I as IQAuthError } from './errors-CDdl24MP.mjs';
|
|
4
|
-
import '
|
|
4
|
+
import './tokens-DCyzzn8L.mjs';
|
|
5
5
|
|
|
6
6
|
declare class ServiceIQAuthClient extends IQAuthClient {
|
|
7
7
|
constructor(config: IQAuthTokenClientConfig);
|
package/dist/service.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { I as IQAuthClient } from './client-
|
|
2
|
-
import { b as IQAuthTokenClientConfig } from './types-
|
|
1
|
+
import { I as IQAuthClient } from './client-BNQe3AgF.js';
|
|
2
|
+
import { b as IQAuthTokenClientConfig } from './types-DZAflmmq.js';
|
|
3
3
|
export { E as ErrorCodes, I as IQAuthError } from './errors-CDdl24MP.js';
|
|
4
|
-
import '
|
|
4
|
+
import './tokens-aHiGFr_E.js';
|
|
5
5
|
|
|
6
6
|
declare class ServiceIQAuthClient extends IQAuthClient {
|
|
7
7
|
constructor(config: IQAuthTokenClientConfig);
|