@eventuras/fides-auth 0.5.0 → 0.7.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/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -5
- package/dist/logger.js +100 -58
- package/dist/logger.js.map +1 -0
- package/dist/oauth-browser.js +52 -30
- package/dist/oauth-browser.js.map +1 -0
- package/dist/oauth-logging.d.ts +45 -0
- package/dist/oauth-logging.d.ts.map +1 -0
- package/dist/oauth-logging.js +50 -0
- package/dist/oauth-logging.js.map +1 -0
- package/dist/oauth.d.ts.map +1 -1
- package/dist/oauth.js +293 -133
- package/dist/oauth.js.map +1 -0
- package/dist/providers/vipps/index.js +162 -76
- package/dist/providers/vipps/index.js.map +1 -0
- package/dist/rate-limit.js +55 -17
- package/dist/rate-limit.js.map +1 -0
- package/dist/session-refresh.d.ts.map +1 -1
- package/dist/session-refresh.js +40 -19
- package/dist/session-refresh.js.map +1 -0
- package/dist/session-validation.js +77 -2
- package/dist/session-validation.js.map +1 -0
- package/dist/silent-login.js +133 -33
- package/dist/silent-login.js.map +1 -0
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils.d.ts +8 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +196 -2
- package/dist/utils.js.map +1 -0
- package/package.json +6 -2
- package/dist/build-nL2--iMi.js +0 -1014
- package/dist/decode_jwt-1J26fl4I.js +0 -25
- package/dist/decrypt-Cahlu_6Y.js +0 -92
- package/dist/deflate-koSuX7FB.js +0 -1015
- package/dist/session-validation-BxObT3wC.js +0 -66
- package/dist/utils-ByMRF7b2.js +0 -379
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,UAAU,CAAC;AACzB,cAAc,mBAAmB,CAAC;AAClC,cAAc,sBAAsB,CAAC;AACrC,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,UAAU,CAAC;AACzB,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,sBAAsB,CAAC;AACrC,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { configureLogger
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import { configureLogger, createLogger } from "./logger.js";
|
|
2
|
+
import { getOAuthConfigLogContext, getOAuthErrorLogContext } from "./oauth-logging.js";
|
|
3
|
+
import { refreshSession } from "./session-refresh.js";
|
|
4
|
+
import { accessTokenExpires, createEncryptedJWT, decrypt, encrypt, generateToken, getSessionSecret, getSessionSecretUint8Array, hasScope, hexToUint8Array, sha256, sha512, toHex } from "./utils.js";
|
|
5
|
+
import { isSession, validateSessionJwt } from "./session-validation.js";
|
|
5
6
|
import "./types.js";
|
|
6
|
-
export {
|
|
7
|
+
export { accessTokenExpires, configureLogger, createEncryptedJWT, createLogger, decrypt, encrypt, generateToken, getOAuthConfigLogContext, getOAuthErrorLogContext, getSessionSecret, getSessionSecretUint8Array, hasScope, hexToUint8Array, isSession, refreshSession, sha256, sha512, toHex, validateSessionJwt };
|
package/dist/logger.js
CHANGED
|
@@ -1,91 +1,133 @@
|
|
|
1
1
|
//#region src/logger.ts
|
|
2
|
-
function
|
|
3
|
-
|
|
4
|
-
name:
|
|
5
|
-
message:
|
|
6
|
-
stack:
|
|
7
|
-
}
|
|
2
|
+
function serializeError(value) {
|
|
3
|
+
if (value instanceof Error) return {
|
|
4
|
+
name: value.name,
|
|
5
|
+
message: value.message,
|
|
6
|
+
stack: value.stack
|
|
7
|
+
};
|
|
8
|
+
return value;
|
|
8
9
|
}
|
|
9
|
-
|
|
10
|
+
/** Field names the logger reserves so callers can't accidentally clobber them. */
|
|
11
|
+
var RESERVED_KEYS = new Set([
|
|
10
12
|
"level",
|
|
11
13
|
"time",
|
|
12
14
|
"namespace"
|
|
13
15
|
]);
|
|
14
|
-
function
|
|
15
|
-
|
|
16
|
+
function safeStringify(record) {
|
|
17
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
16
18
|
try {
|
|
17
|
-
return JSON.stringify(
|
|
18
|
-
if (
|
|
19
|
-
if (typeof
|
|
20
|
-
if (typeof
|
|
21
|
-
if (
|
|
22
|
-
|
|
19
|
+
return JSON.stringify(record, (_key, value) => {
|
|
20
|
+
if (value instanceof Error) return serializeError(value);
|
|
21
|
+
if (typeof value === "bigint") return value.toString();
|
|
22
|
+
if (typeof value === "object" && value !== null) {
|
|
23
|
+
if (seen.has(value)) return "[Circular]";
|
|
24
|
+
seen.add(value);
|
|
23
25
|
}
|
|
24
|
-
return
|
|
26
|
+
return value;
|
|
25
27
|
});
|
|
26
28
|
} catch {
|
|
27
29
|
return JSON.stringify({
|
|
28
|
-
level:
|
|
29
|
-
time:
|
|
30
|
-
namespace:
|
|
31
|
-
msg: typeof
|
|
32
|
-
_serializeError:
|
|
30
|
+
level: record.level,
|
|
31
|
+
time: record.time,
|
|
32
|
+
namespace: record.namespace,
|
|
33
|
+
msg: typeof record.msg === "string" ? record.msg : "[unserializable log entry]",
|
|
34
|
+
_serializeError: true
|
|
33
35
|
});
|
|
34
36
|
}
|
|
35
37
|
}
|
|
36
|
-
var
|
|
37
|
-
constructor(
|
|
38
|
-
this.namespace =
|
|
38
|
+
var ConsoleLogger = class {
|
|
39
|
+
constructor(namespace, context) {
|
|
40
|
+
this.namespace = namespace;
|
|
41
|
+
this.context = context;
|
|
39
42
|
}
|
|
40
|
-
write(
|
|
41
|
-
if (
|
|
42
|
-
|
|
43
|
-
level
|
|
43
|
+
write(method, level, data, msg) {
|
|
44
|
+
if (data === void 0 && msg === void 0) return;
|
|
45
|
+
const entry = {
|
|
46
|
+
level,
|
|
44
47
|
time: (/* @__PURE__ */ new Date()).toISOString(),
|
|
45
48
|
namespace: this.namespace
|
|
46
49
|
};
|
|
47
|
-
if (this.context)
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
50
|
+
if (this.context) {
|
|
51
|
+
for (const [key, value] of Object.entries(this.context)) if (!RESERVED_KEYS.has(key)) entry[key] = value;
|
|
52
|
+
}
|
|
53
|
+
if (typeof data === "string") entry.msg = data;
|
|
54
|
+
else {
|
|
55
|
+
if (msg !== void 0) entry.msg = msg;
|
|
56
|
+
if (data) {
|
|
57
|
+
for (const [key, value] of Object.entries(data)) if (!RESERVED_KEYS.has(key)) entry[key] = value;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
if (entry.error !== void 0) entry.error = serializeError(entry.error);
|
|
61
|
+
console[method](safeStringify(entry));
|
|
51
62
|
}
|
|
52
|
-
debug(
|
|
53
|
-
this.write("debug", "debug",
|
|
63
|
+
debug(data, msg) {
|
|
64
|
+
this.write("debug", "debug", data, msg);
|
|
54
65
|
}
|
|
55
|
-
info(
|
|
56
|
-
this.write("info", "info",
|
|
66
|
+
info(data, msg) {
|
|
67
|
+
this.write("info", "info", data, msg);
|
|
57
68
|
}
|
|
58
|
-
warn(
|
|
59
|
-
this.write("warn", "warn",
|
|
69
|
+
warn(data, msg) {
|
|
70
|
+
this.write("warn", "warn", data, msg);
|
|
60
71
|
}
|
|
61
|
-
error(
|
|
62
|
-
this.write("error", "error",
|
|
72
|
+
error(data, msg) {
|
|
73
|
+
this.write("error", "error", data, msg);
|
|
63
74
|
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
75
|
+
};
|
|
76
|
+
var currentFactory = { create({ namespace, context }) {
|
|
77
|
+
return new ConsoleLogger(namespace, context);
|
|
78
|
+
} };
|
|
79
|
+
var factoryVersion = 0;
|
|
80
|
+
/**
|
|
81
|
+
* Configure a custom logger factory for fides-auth.
|
|
82
|
+
*
|
|
83
|
+
* Can be called at any time — even after modules have already created loggers.
|
|
84
|
+
* Existing loggers will pick up the new factory on their next log call.
|
|
85
|
+
*
|
|
86
|
+
* If not called, fides-auth uses a console-based logger.
|
|
87
|
+
*
|
|
88
|
+
* @param factory - A factory that creates logger instances
|
|
89
|
+
*/
|
|
90
|
+
function configureLogger(factory) {
|
|
91
|
+
currentFactory = factory;
|
|
92
|
+
factoryVersion++;
|
|
69
93
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
94
|
+
/**
|
|
95
|
+
* Create a logger instance using the configured factory.
|
|
96
|
+
*
|
|
97
|
+
* Returns a lazy proxy: the underlying logger is created (or re-created)
|
|
98
|
+
* on first use and whenever the factory is changed via `configureLogger()`.
|
|
99
|
+
* This means module-scope loggers work correctly even when `configureLogger()`
|
|
100
|
+
* is called after module imports.
|
|
101
|
+
*
|
|
102
|
+
* @param options - Logger options including namespace and optional context
|
|
103
|
+
* @returns A logger instance
|
|
104
|
+
*/
|
|
105
|
+
function createLogger(options) {
|
|
106
|
+
let cached = null;
|
|
107
|
+
let cachedVersion = -1;
|
|
108
|
+
function resolve() {
|
|
109
|
+
if (cached === null || cachedVersion !== factoryVersion) {
|
|
110
|
+
cached = currentFactory.create(options);
|
|
111
|
+
cachedVersion = factoryVersion;
|
|
112
|
+
}
|
|
113
|
+
return cached;
|
|
74
114
|
}
|
|
75
115
|
return {
|
|
76
|
-
debug(
|
|
77
|
-
|
|
116
|
+
debug(data, msg) {
|
|
117
|
+
resolve().debug(data, msg);
|
|
78
118
|
},
|
|
79
|
-
info(
|
|
80
|
-
|
|
119
|
+
info(data, msg) {
|
|
120
|
+
resolve().info(data, msg);
|
|
81
121
|
},
|
|
82
|
-
warn(
|
|
83
|
-
|
|
122
|
+
warn(data, msg) {
|
|
123
|
+
resolve().warn(data, msg);
|
|
84
124
|
},
|
|
85
|
-
error(
|
|
86
|
-
|
|
125
|
+
error(data, msg) {
|
|
126
|
+
resolve().error(data, msg);
|
|
87
127
|
}
|
|
88
128
|
};
|
|
89
129
|
}
|
|
90
130
|
//#endregion
|
|
91
|
-
export {
|
|
131
|
+
export { configureLogger, createLogger };
|
|
132
|
+
|
|
133
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","names":[],"sources":["../src/logger.ts"],"sourcesContent":["/**\n * Pluggable logger for fides-auth.\n *\n * The default writes newline-delimited JSON to `console.<level>` so output\n * is interoperable with Loki / Grafana / Datadog out of the box, even when\n * the consumer hasn't wired in a structured logger. Users can plug their\n * own backend (pino, winston, @eventuras/logger, ...) via `configureLogger()`.\n *\n * @example\n * // Use default JSONL console logger (no setup needed)\n * import { createLogger } from '@eventuras/fides-auth/logger';\n * const logger = createLogger({ namespace: 'my-app:auth' });\n * logger.info('Authentication successful');\n * // → {\"level\":\"info\",\"time\":\"…\",\"namespace\":\"my-app:auth\",\"msg\":\"Authentication successful\"}\n *\n * @example\n * // Plug in pino\n * import pino from 'pino';\n * import { configureLogger } from '@eventuras/fides-auth/logger';\n *\n * const pinoInstance = pino();\n * configureLogger({\n * create({ namespace, context }) {\n * return pinoInstance.child({ namespace, ...context });\n * },\n * });\n *\n * @example\n * // Plug in @eventuras/logger\n * import { Logger } from '@eventuras/logger';\n * import { configureLogger } from '@eventuras/fides-auth/logger';\n *\n * configureLogger({\n * create(options) {\n * return Logger.create(options);\n * },\n * });\n */\n\n/**\n * Logger interface compatible with pino, winston, and console.\n *\n * All methods accept either:\n * - A string message: `logger.info('hello')`\n * - A context object and message: `logger.info({ userId: 123 }, 'User logged in')`\n */\nexport interface FidesLogger {\n debug(data?: Record<string, unknown> | string, msg?: string): void;\n info(data?: Record<string, unknown> | string, msg?: string): void;\n warn(data?: Record<string, unknown> | string, msg?: string): void;\n error(data?: Record<string, unknown> | string, msg?: string): void;\n}\n\n/** Options for creating a logger instance. */\nexport interface FidesLoggerOptions {\n /** Namespace for log filtering (e.g., 'fides-auth:oauth') */\n namespace: string;\n /** Persistent context fields included in every log entry */\n context?: Record<string, unknown>;\n}\n\n/** Factory that creates logger instances. Implement this to integrate your preferred logger. */\nexport interface FidesLoggerFactory {\n create(options: FidesLoggerOptions): FidesLogger;\n}\n\n/**\n * Console-based logger implementation that emits newline-delimited JSON.\n *\n * Used as the default when no custom logger factory is configured. JSONL\n * keeps fides-auth's output interoperable with log shippers (Loki, Grafana,\n * Datadog, etc.) even when the consuming app hasn't wired in a structured\n * logger via `configureLogger()`. Each entry preserves the original\n * `console.<level>` call so browser devtools and CI log filters still work.\n *\n * Output shape (example):\n *\n * {\"level\":\"info\",\"time\":\"2026-04-15T19:40:57.300Z\",\"namespace\":\"fides-auth:oauth\",\"msg\":\"PKCE parameters generated\",\"codeChallenge\":\"…\"}\n *\n * Errors in the `data` field are serialized to `{ name, message, stack }`\n * so they survive `JSON.stringify`.\n */\ntype ConsoleMethod = 'debug' | 'info' | 'warn' | 'error';\n\nfunction serializeError(value: unknown): unknown {\n if (value instanceof Error) {\n return { name: value.name, message: value.message, stack: value.stack };\n }\n return value;\n}\n\n/** Field names the logger reserves so callers can't accidentally clobber them. */\nconst RESERVED_KEYS = new Set(['level', 'time', 'namespace']);\n\nfunction safeStringify(record: Record<string, unknown>): string {\n const seen = new WeakSet<object>();\n try {\n return JSON.stringify(record, (_key, value) => {\n if (value instanceof Error) return serializeError(value);\n if (typeof value === 'bigint') return value.toString();\n if (typeof value === 'object' && value !== null) {\n if (seen.has(value)) return '[Circular]';\n seen.add(value);\n }\n return value;\n });\n } catch {\n // Last-resort fallback: drop the original record entirely so a single\n // non-serializable payload can't take down the caller's request path.\n return JSON.stringify({\n level: record.level,\n time: record.time,\n namespace: record.namespace,\n msg: typeof record.msg === 'string' ? record.msg : '[unserializable log entry]',\n _serializeError: true,\n });\n }\n}\n\nclass ConsoleLogger implements FidesLogger {\n constructor(\n private readonly namespace: string,\n private readonly context?: Record<string, unknown>,\n ) { }\n\n private write(\n method: ConsoleMethod,\n level: 'debug' | 'info' | 'warn' | 'error',\n data?: Record<string, unknown> | string,\n msg?: string,\n ): void {\n // Skip noisy empty entries — match the pre-JSON ConsoleLogger, which\n // dropped calls with no data and no message.\n if (data === undefined && msg === undefined) return;\n\n // Reserved keys are set first so they appear at the front of the JSON\n // output. User-supplied fields are filtered against RESERVED_KEYS so\n // they can't clobber level/time/namespace.\n const entry: Record<string, unknown> = {\n level,\n time: new Date().toISOString(),\n namespace: this.namespace,\n };\n\n if (this.context) {\n for (const [key, value] of Object.entries(this.context)) {\n if (!RESERVED_KEYS.has(key)) entry[key] = value;\n }\n }\n\n if (typeof data === 'string') {\n entry.msg = data;\n } else {\n if (msg !== undefined) entry.msg = msg;\n if (data) {\n for (const [key, value] of Object.entries(data)) {\n if (!RESERVED_KEYS.has(key)) entry[key] = value;\n }\n }\n }\n\n if (entry.error !== undefined) {\n entry.error = serializeError(entry.error);\n }\n\n console[method](safeStringify(entry));\n }\n\n debug(data?: Record<string, unknown> | string, msg?: string): void {\n this.write('debug', 'debug', data, msg);\n }\n\n info(data?: Record<string, unknown> | string, msg?: string): void {\n this.write('info', 'info', data, msg);\n }\n\n warn(data?: Record<string, unknown> | string, msg?: string): void {\n this.write('warn', 'warn', data, msg);\n }\n\n error(data?: Record<string, unknown> | string, msg?: string): void {\n this.write('error', 'error', data, msg);\n }\n}\n\nconst defaultFactory: FidesLoggerFactory = {\n create({ namespace, context }) {\n return new ConsoleLogger(namespace, context);\n },\n};\n\nlet currentFactory: FidesLoggerFactory = defaultFactory;\nlet factoryVersion = 0;\n\n/**\n * Configure a custom logger factory for fides-auth.\n *\n * Can be called at any time — even after modules have already created loggers.\n * Existing loggers will pick up the new factory on their next log call.\n *\n * If not called, fides-auth uses a console-based logger.\n *\n * @param factory - A factory that creates logger instances\n */\nexport function configureLogger(factory: FidesLoggerFactory): void {\n currentFactory = factory;\n factoryVersion++;\n}\n\n/**\n * Create a logger instance using the configured factory.\n *\n * Returns a lazy proxy: the underlying logger is created (or re-created)\n * on first use and whenever the factory is changed via `configureLogger()`.\n * This means module-scope loggers work correctly even when `configureLogger()`\n * is called after module imports.\n *\n * @param options - Logger options including namespace and optional context\n * @returns A logger instance\n */\nexport function createLogger(options: FidesLoggerOptions): FidesLogger {\n let cached: FidesLogger | null = null;\n let cachedVersion = -1;\n\n function resolve(): FidesLogger {\n if (cached === null || cachedVersion !== factoryVersion) {\n cached = currentFactory.create(options);\n cachedVersion = factoryVersion;\n }\n return cached;\n }\n\n return {\n debug(data?, msg?) { resolve().debug(data, msg); },\n info(data?, msg?) { resolve().info(data, msg); },\n warn(data?, msg?) { resolve().warn(data, msg); },\n error(data?, msg?) { resolve().error(data, msg); },\n };\n}\n"],"mappings":";AAoFA,SAAS,eAAe,OAAyB;AAC/C,KAAI,iBAAiB,MACnB,QAAO;EAAE,MAAM,MAAM;EAAM,SAAS,MAAM;EAAS,OAAO,MAAM;EAAO;AAEzE,QAAO;;;AAIT,IAAM,gBAAgB,IAAI,IAAI;CAAC;CAAS;CAAQ;CAAY,CAAC;AAE7D,SAAS,cAAc,QAAyC;CAC9D,MAAM,uBAAO,IAAI,SAAiB;AAClC,KAAI;AACF,SAAO,KAAK,UAAU,SAAS,MAAM,UAAU;AAC7C,OAAI,iBAAiB,MAAO,QAAO,eAAe,MAAM;AACxD,OAAI,OAAO,UAAU,SAAU,QAAO,MAAM,UAAU;AACtD,OAAI,OAAO,UAAU,YAAY,UAAU,MAAM;AAC/C,QAAI,KAAK,IAAI,MAAM,CAAE,QAAO;AAC5B,SAAK,IAAI,MAAM;;AAEjB,UAAO;IACP;SACI;AAGN,SAAO,KAAK,UAAU;GACpB,OAAO,OAAO;GACd,MAAM,OAAO;GACb,WAAW,OAAO;GAClB,KAAK,OAAO,OAAO,QAAQ,WAAW,OAAO,MAAM;GACnD,iBAAiB;GAClB,CAAC;;;AAIN,IAAM,gBAAN,MAA2C;CACzC,YACE,WACA,SACA;AAFiB,OAAA,YAAA;AACA,OAAA,UAAA;;CAGnB,MACE,QACA,OACA,MACA,KACM;AAGN,MAAI,SAAS,KAAA,KAAa,QAAQ,KAAA,EAAW;EAK7C,MAAM,QAAiC;GACrC;GACA,uBAAM,IAAI,MAAM,EAAC,aAAa;GAC9B,WAAW,KAAK;GACjB;AAED,MAAI,KAAK;QACF,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,KAAK,QAAQ,CACrD,KAAI,CAAC,cAAc,IAAI,IAAI,CAAE,OAAM,OAAO;;AAI9C,MAAI,OAAO,SAAS,SAClB,OAAM,MAAM;OACP;AACL,OAAI,QAAQ,KAAA,EAAW,OAAM,MAAM;AACnC,OAAI;SACG,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,KAAK,CAC7C,KAAI,CAAC,cAAc,IAAI,IAAI,CAAE,OAAM,OAAO;;;AAKhD,MAAI,MAAM,UAAU,KAAA,EAClB,OAAM,QAAQ,eAAe,MAAM,MAAM;AAG3C,UAAQ,QAAQ,cAAc,MAAM,CAAC;;CAGvC,MAAM,MAAyC,KAAoB;AACjE,OAAK,MAAM,SAAS,SAAS,MAAM,IAAI;;CAGzC,KAAK,MAAyC,KAAoB;AAChE,OAAK,MAAM,QAAQ,QAAQ,MAAM,IAAI;;CAGvC,KAAK,MAAyC,KAAoB;AAChE,OAAK,MAAM,QAAQ,QAAQ,MAAM,IAAI;;CAGvC,MAAM,MAAyC,KAAoB;AACjE,OAAK,MAAM,SAAS,SAAS,MAAM,IAAI;;;AAU3C,IAAI,iBAAqC,EALvC,OAAO,EAAE,WAAW,WAAW;AAC7B,QAAO,IAAI,cAAc,WAAW,QAAQ;GAIP;AACzC,IAAI,iBAAiB;;;;;;;;;;;AAYrB,SAAgB,gBAAgB,SAAmC;AACjE,kBAAiB;AACjB;;;;;;;;;;;;;AAcF,SAAgB,aAAa,SAA0C;CACrE,IAAI,SAA6B;CACjC,IAAI,gBAAgB;CAEpB,SAAS,UAAuB;AAC9B,MAAI,WAAW,QAAQ,kBAAkB,gBAAgB;AACvD,YAAS,eAAe,OAAO,QAAQ;AACvC,mBAAgB;;AAElB,SAAO;;AAGT,QAAO;EACL,MAAM,MAAO,KAAM;AAAE,YAAS,CAAC,MAAM,MAAM,IAAI;;EAC/C,KAAK,MAAO,KAAM;AAAE,YAAS,CAAC,KAAK,MAAM,IAAI;;EAC7C,KAAK,MAAO,KAAM;AAAE,YAAS,CAAC,KAAK,MAAM,IAAI;;EAC7C,MAAM,MAAO,KAAM;AAAE,YAAS,CAAC,MAAM,MAAM,IAAI;;EAChD"}
|
package/dist/oauth-browser.js
CHANGED
|
@@ -1,49 +1,71 @@
|
|
|
1
1
|
//#region src/oauth-browser.ts
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
/**
|
|
3
|
+
* Generate random string for code verifier (PKCE)
|
|
4
|
+
* Uses Web Crypto API (browser-compatible)
|
|
5
|
+
*/
|
|
6
|
+
function generateRandomString(length) {
|
|
7
|
+
const charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~";
|
|
8
|
+
const randomValues = new Uint8Array(length);
|
|
9
|
+
crypto.getRandomValues(randomValues);
|
|
10
|
+
return Array.from(randomValues).map((x) => charset[x % 66]).join("");
|
|
5
11
|
}
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
12
|
+
/**
|
|
13
|
+
* Generate PKCE code challenge from verifier
|
|
14
|
+
* Uses Web Crypto API SHA-256
|
|
15
|
+
*/
|
|
16
|
+
async function generateCodeChallenge(verifier) {
|
|
17
|
+
const data = new TextEncoder().encode(verifier);
|
|
18
|
+
const hash = await crypto.subtle.digest("SHA-256", data);
|
|
19
|
+
return btoa(String.fromCharCode(...new Uint8Array(hash))).replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/, "");
|
|
9
20
|
}
|
|
10
|
-
|
|
11
|
-
|
|
21
|
+
/**
|
|
22
|
+
* Generate PKCE parameters for OAuth flow
|
|
23
|
+
*/
|
|
24
|
+
async function generatePKCE() {
|
|
25
|
+
const code_verifier = generateRandomString(128);
|
|
12
26
|
return {
|
|
13
|
-
code_verifier
|
|
14
|
-
code_challenge: await
|
|
15
|
-
state:
|
|
27
|
+
code_verifier,
|
|
28
|
+
code_challenge: await generateCodeChallenge(code_verifier),
|
|
29
|
+
state: generateRandomString(32)
|
|
16
30
|
};
|
|
17
31
|
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
32
|
+
/**
|
|
33
|
+
* Build authorization URL for OAuth flow
|
|
34
|
+
*/
|
|
35
|
+
function buildAuthorizationUrl(config, pkce) {
|
|
36
|
+
const params = new URLSearchParams({
|
|
37
|
+
client_id: config.clientId,
|
|
38
|
+
redirect_uri: config.redirect_uri,
|
|
22
39
|
response_type: "code",
|
|
23
|
-
scope:
|
|
24
|
-
state:
|
|
25
|
-
code_challenge:
|
|
40
|
+
scope: config.scope,
|
|
41
|
+
state: pkce.state,
|
|
42
|
+
code_challenge: pkce.code_challenge,
|
|
26
43
|
code_challenge_method: "S256"
|
|
27
44
|
});
|
|
28
|
-
return `${
|
|
45
|
+
return `${config.issuer}/auth?${params.toString()}`;
|
|
29
46
|
}
|
|
30
|
-
|
|
31
|
-
|
|
47
|
+
/**
|
|
48
|
+
* Exchange authorization code for tokens
|
|
49
|
+
*/
|
|
50
|
+
async function exchangeCodeForTokens(config, code, codeVerifier) {
|
|
51
|
+
const response = await fetch(`${config.issuer}/token`, {
|
|
32
52
|
method: "POST",
|
|
33
53
|
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
34
54
|
body: new URLSearchParams({
|
|
35
55
|
grant_type: "authorization_code",
|
|
36
|
-
code
|
|
37
|
-
redirect_uri:
|
|
38
|
-
client_id:
|
|
39
|
-
code_verifier:
|
|
56
|
+
code,
|
|
57
|
+
redirect_uri: config.redirect_uri,
|
|
58
|
+
client_id: config.clientId,
|
|
59
|
+
code_verifier: codeVerifier
|
|
40
60
|
})
|
|
41
61
|
});
|
|
42
|
-
if (!
|
|
43
|
-
|
|
44
|
-
throw Error(`Token exchange failed: ${
|
|
62
|
+
if (!response.ok) {
|
|
63
|
+
const error = await response.text();
|
|
64
|
+
throw new Error(`Token exchange failed: ${response.status} - ${error}`);
|
|
45
65
|
}
|
|
46
|
-
return
|
|
66
|
+
return response.json();
|
|
47
67
|
}
|
|
48
68
|
//#endregion
|
|
49
|
-
export {
|
|
69
|
+
export { buildAuthorizationUrl, exchangeCodeForTokens, generatePKCE };
|
|
70
|
+
|
|
71
|
+
//# sourceMappingURL=oauth-browser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth-browser.js","names":[],"sources":["../src/oauth-browser.ts"],"sourcesContent":["/**\n * Browser-compatible OAuth 2.0 + PKCE helpers\n *\n * This module provides OAuth 2.0 helpers that work in browser environments.\n * Unlike `oauth.ts` which uses openid-client (Node.js only), this uses\n * browser-native Web Crypto API for PKCE generation.\n *\n * **Use this in:**\n * - Vite/React SPAs\n * - Browser-only applications\n * - Any frontend that can't use Node.js APIs\n *\n * **Usage:**\n * ```typescript\n * import { generatePKCE, buildAuthorizationUrl, exchangeCodeForTokens }\n * from '@eventuras/fides-auth/oauth-browser';\n *\n * // 1. Start OAuth flow\n * const pkce = await generatePKCE();\n * sessionStorage.setItem('code_verifier', pkce.code_verifier);\n * sessionStorage.setItem('state', pkce.state);\n *\n * const authUrl = buildAuthorizationUrl(config, pkce);\n * window.location.href = authUrl;\n *\n * // 2. Handle callback\n * const code = new URLSearchParams(window.location.search).get('code');\n * const verifier = sessionStorage.getItem('code_verifier');\n * const tokens = await exchangeCodeForTokens(config, code, verifier);\n * ```\n */\n\n/** Configuration for browser-side OAuth / OIDC flows (no client secret). */\nexport interface OAuthConfig {\n issuer: string;\n clientId: string;\n redirect_uri: string;\n scope: string;\n}\n\n/** PKCE parameters for a browser-initiated authorization request. */\nexport interface PKCEParams {\n code_verifier: string;\n code_challenge: string;\n state: string;\n}\n\n/**\n * Generate random string for code verifier (PKCE)\n * Uses Web Crypto API (browser-compatible)\n */\nfunction generateRandomString(length: number): string {\n const charset = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~';\n const randomValues = new Uint8Array(length);\n crypto.getRandomValues(randomValues);\n return Array.from(randomValues)\n .map((x) => charset[x % charset.length])\n .join('');\n}\n\n/**\n * Generate PKCE code challenge from verifier\n * Uses Web Crypto API SHA-256\n */\nasync function generateCodeChallenge(verifier: string): Promise<string> {\n const encoder = new TextEncoder();\n const data = encoder.encode(verifier);\n const hash = await crypto.subtle.digest('SHA-256', data);\n\n // Base64URL encode\n return btoa(String.fromCharCode(...new Uint8Array(hash)))\n .replaceAll('+', '-')\n .replaceAll('/', '_')\n .replace(/=+$/, '');\n}\n\n/**\n * Generate PKCE parameters for OAuth flow\n */\nexport async function generatePKCE(): Promise<PKCEParams> {\n const code_verifier = generateRandomString(128);\n const code_challenge = await generateCodeChallenge(code_verifier);\n const state = generateRandomString(32);\n\n return {\n code_verifier,\n code_challenge,\n state,\n };\n}\n\n/**\n * Build authorization URL for OAuth flow\n */\nexport function buildAuthorizationUrl(\n config: OAuthConfig,\n pkce: PKCEParams\n): string {\n const params = new URLSearchParams({\n client_id: config.clientId,\n redirect_uri: config.redirect_uri,\n response_type: 'code',\n scope: config.scope,\n state: pkce.state,\n code_challenge: pkce.code_challenge,\n code_challenge_method: 'S256',\n });\n\n return `${config.issuer}/auth?${params.toString()}`;\n}\n\n/**\n * Exchange authorization code for tokens\n */\nexport async function exchangeCodeForTokens(\n config: OAuthConfig,\n code: string,\n codeVerifier: string\n): Promise<{\n access_token: string;\n id_token: string;\n refresh_token?: string;\n expires_in: number;\n}> {\n const response = await fetch(`${config.issuer}/token`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: new URLSearchParams({\n grant_type: 'authorization_code',\n code,\n redirect_uri: config.redirect_uri,\n client_id: config.clientId,\n code_verifier: codeVerifier,\n }),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Token exchange failed: ${response.status} - ${error}`);\n }\n\n return response.json();\n}\n"],"mappings":";;;;;AAmDA,SAAS,qBAAqB,QAAwB;CACpD,MAAM,UAAU;CAChB,MAAM,eAAe,IAAI,WAAW,OAAO;AAC3C,QAAO,gBAAgB,aAAa;AACpC,QAAO,MAAM,KAAK,aAAa,CAC5B,KAAK,MAAM,QAAQ,IAAI,IAAgB,CACvC,KAAK,GAAG;;;;;;AAOb,eAAe,sBAAsB,UAAmC;CAEtE,MAAM,OAAO,IADO,aACP,CAAQ,OAAO,SAAS;CACrC,MAAM,OAAO,MAAM,OAAO,OAAO,OAAO,WAAW,KAAK;AAGxD,QAAO,KAAK,OAAO,aAAa,GAAG,IAAI,WAAW,KAAK,CAAC,CAAC,CACtD,WAAW,KAAK,IAAI,CACpB,WAAW,KAAK,IAAI,CACpB,QAAQ,OAAO,GAAG;;;;;AAMvB,eAAsB,eAAoC;CACxD,MAAM,gBAAgB,qBAAqB,IAAI;AAI/C,QAAO;EACL;EACA,gBAAA,MAL2B,sBAAsB,cAAc;EAM/D,OALY,qBAAqB,GAKjC;EACD;;;;;AAMH,SAAgB,sBACd,QACA,MACQ;CACR,MAAM,SAAS,IAAI,gBAAgB;EACjC,WAAW,OAAO;EAClB,cAAc,OAAO;EACrB,eAAe;EACf,OAAO,OAAO;EACd,OAAO,KAAK;EACZ,gBAAgB,KAAK;EACrB,uBAAuB;EACxB,CAAC;AAEF,QAAO,GAAG,OAAO,OAAO,QAAQ,OAAO,UAAU;;;;;AAMnD,eAAsB,sBACpB,QACA,MACA,cAMC;CACD,MAAM,WAAW,MAAM,MAAM,GAAG,OAAO,OAAO,SAAS;EACrD,QAAQ;EACR,SAAS,EACP,gBAAgB,qCACjB;EACD,MAAM,IAAI,gBAAgB;GACxB,YAAY;GACZ;GACA,cAAc,OAAO;GACrB,WAAW,OAAO;GAClB,eAAe;GAChB,CAAC;EACH,CAAC;AAEF,KAAI,CAAC,SAAS,IAAI;EAChB,MAAM,QAAQ,MAAM,SAAS,MAAM;AACnC,QAAM,IAAI,MAAM,0BAA0B,SAAS,OAAO,KAAK,QAAQ;;AAGzE,QAAO,SAAS,MAAM"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { OAuthConfig } from './oauth';
|
|
2
|
+
/**
|
|
3
|
+
* Returns a structured, log-safe context describing an `OAuthConfig`.
|
|
4
|
+
*
|
|
5
|
+
* Excludes `clientSecret`. Use this to attach provider configuration to log
|
|
6
|
+
* lines for debugging OAuth/OIDC flows without leaking credentials.
|
|
7
|
+
*/
|
|
8
|
+
export declare function getOAuthConfigLogContext(config: OAuthConfig): {
|
|
9
|
+
clientId: string;
|
|
10
|
+
issuer: string;
|
|
11
|
+
redirectUri: string;
|
|
12
|
+
scope: string;
|
|
13
|
+
usePar: boolean;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Returns a structured log context for an unknown OAuth-related error.
|
|
17
|
+
*
|
|
18
|
+
* `oauth4webapi` (used via `openid-client`) wraps OAuth response errors. The
|
|
19
|
+
* original OAuth response (`{error, error_description, ...}`) usually lives
|
|
20
|
+
* either on the error itself or on `cause`.
|
|
21
|
+
*
|
|
22
|
+
* @see https://github.com/panva/oauth4webapi/blob/main/docs/classes/ResponseBodyError.md
|
|
23
|
+
*/
|
|
24
|
+
export declare function getOAuthErrorLogContext(error: unknown): {
|
|
25
|
+
value: unknown;
|
|
26
|
+
code?: undefined;
|
|
27
|
+
error?: undefined;
|
|
28
|
+
errorDescription?: undefined;
|
|
29
|
+
message?: undefined;
|
|
30
|
+
name?: undefined;
|
|
31
|
+
status?: undefined;
|
|
32
|
+
causeMessage?: undefined;
|
|
33
|
+
causeName?: undefined;
|
|
34
|
+
} | {
|
|
35
|
+
code: string | undefined;
|
|
36
|
+
error: string | undefined;
|
|
37
|
+
errorDescription: string | undefined;
|
|
38
|
+
message: string | undefined;
|
|
39
|
+
name: string | undefined;
|
|
40
|
+
status: number | undefined;
|
|
41
|
+
causeMessage: string | undefined;
|
|
42
|
+
causeName: string | undefined;
|
|
43
|
+
value?: undefined;
|
|
44
|
+
};
|
|
45
|
+
//# sourceMappingURL=oauth-logging.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth-logging.d.ts","sourceRoot":"","sources":["../src/oauth-logging.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAE3C;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,WAAW;;;;;;EAQ3D;AAED;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;EA0BrD"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
//#region src/oauth-logging.ts
|
|
2
|
+
/**
|
|
3
|
+
* Returns a structured, log-safe context describing an `OAuthConfig`.
|
|
4
|
+
*
|
|
5
|
+
* Excludes `clientSecret`. Use this to attach provider configuration to log
|
|
6
|
+
* lines for debugging OAuth/OIDC flows without leaking credentials.
|
|
7
|
+
*/
|
|
8
|
+
function getOAuthConfigLogContext(config) {
|
|
9
|
+
return {
|
|
10
|
+
clientId: config.clientId,
|
|
11
|
+
issuer: config.issuer,
|
|
12
|
+
redirectUri: config.redirect_uri,
|
|
13
|
+
scope: config.scope,
|
|
14
|
+
usePar: config.usePar ?? false
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Returns a structured log context for an unknown OAuth-related error.
|
|
19
|
+
*
|
|
20
|
+
* `oauth4webapi` (used via `openid-client`) wraps OAuth response errors. The
|
|
21
|
+
* original OAuth response (`{error, error_description, ...}`) usually lives
|
|
22
|
+
* either on the error itself or on `cause`.
|
|
23
|
+
*
|
|
24
|
+
* @see https://github.com/panva/oauth4webapi/blob/main/docs/classes/ResponseBodyError.md
|
|
25
|
+
*/
|
|
26
|
+
function getOAuthErrorLogContext(error) {
|
|
27
|
+
if (typeof error !== "object" || error === null) return { value: error };
|
|
28
|
+
const candidate = error;
|
|
29
|
+
const cause = typeof candidate.cause === "object" && candidate.cause !== null ? candidate.cause : null;
|
|
30
|
+
return {
|
|
31
|
+
code: stringProp(candidate, "code") ?? (cause ? stringProp(cause, "code") : void 0),
|
|
32
|
+
error: stringProp(candidate, "error") ?? (cause ? stringProp(cause, "error") : void 0),
|
|
33
|
+
errorDescription: stringProp(candidate, "error_description") ?? (cause ? stringProp(cause, "error_description") : void 0),
|
|
34
|
+
message: stringProp(candidate, "message"),
|
|
35
|
+
name: stringProp(candidate, "name"),
|
|
36
|
+
status: numberProp(candidate, "status"),
|
|
37
|
+
causeMessage: cause ? stringProp(cause, "message") : void 0,
|
|
38
|
+
causeName: cause ? stringProp(cause, "name") : void 0
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
function stringProp(value, key) {
|
|
42
|
+
return typeof value[key] === "string" ? value[key] : void 0;
|
|
43
|
+
}
|
|
44
|
+
function numberProp(value, key) {
|
|
45
|
+
return typeof value[key] === "number" ? value[key] : void 0;
|
|
46
|
+
}
|
|
47
|
+
//#endregion
|
|
48
|
+
export { getOAuthConfigLogContext, getOAuthErrorLogContext };
|
|
49
|
+
|
|
50
|
+
//# sourceMappingURL=oauth-logging.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth-logging.js","names":[],"sources":["../src/oauth-logging.ts"],"sourcesContent":["import type { OAuthConfig } from './oauth';\n\n/**\n * Returns a structured, log-safe context describing an `OAuthConfig`.\n *\n * Excludes `clientSecret`. Use this to attach provider configuration to log\n * lines for debugging OAuth/OIDC flows without leaking credentials.\n */\nexport function getOAuthConfigLogContext(config: OAuthConfig) {\n return {\n clientId: config.clientId,\n issuer: config.issuer,\n redirectUri: config.redirect_uri,\n scope: config.scope,\n usePar: config.usePar ?? false,\n };\n}\n\n/**\n * Returns a structured log context for an unknown OAuth-related error.\n *\n * `oauth4webapi` (used via `openid-client`) wraps OAuth response errors. The\n * original OAuth response (`{error, error_description, ...}`) usually lives\n * either on the error itself or on `cause`.\n *\n * @see https://github.com/panva/oauth4webapi/blob/main/docs/classes/ResponseBodyError.md\n */\nexport function getOAuthErrorLogContext(error: unknown) {\n if (typeof error !== 'object' || error === null) {\n return { value: error };\n }\n\n const candidate = error as Record<string, unknown>;\n const cause =\n typeof candidate.cause === 'object' && candidate.cause !== null\n ? (candidate.cause as Record<string, unknown>)\n : null;\n\n // OAuth-specific fields (code/error/error_description) may live either on\n // the error itself or on `cause` depending on how oauth4webapi wraps the\n // response. Prefer the top-level value but fall back to `cause`.\n return {\n code: stringProp(candidate, 'code') ?? (cause ? stringProp(cause, 'code') : undefined),\n error: stringProp(candidate, 'error') ?? (cause ? stringProp(cause, 'error') : undefined),\n errorDescription:\n stringProp(candidate, 'error_description') ??\n (cause ? stringProp(cause, 'error_description') : undefined),\n message: stringProp(candidate, 'message'),\n name: stringProp(candidate, 'name'),\n status: numberProp(candidate, 'status'),\n causeMessage: cause ? stringProp(cause, 'message') : undefined,\n causeName: cause ? stringProp(cause, 'name') : undefined,\n };\n}\n\nfunction stringProp(value: Record<string, unknown>, key: string): string | undefined {\n return typeof value[key] === 'string' ? (value[key] as string) : undefined;\n}\n\nfunction numberProp(value: Record<string, unknown>, key: string): number | undefined {\n return typeof value[key] === 'number' ? (value[key] as number) : undefined;\n}\n"],"mappings":";;;;;;;AAQA,SAAgB,yBAAyB,QAAqB;AAC5D,QAAO;EACL,UAAU,OAAO;EACjB,QAAQ,OAAO;EACf,aAAa,OAAO;EACpB,OAAO,OAAO;EACd,QAAQ,OAAO,UAAU;EAC1B;;;;;;;;;;;AAYH,SAAgB,wBAAwB,OAAgB;AACtD,KAAI,OAAO,UAAU,YAAY,UAAU,KACzC,QAAO,EAAE,OAAO,OAAO;CAGzB,MAAM,YAAY;CAClB,MAAM,QACJ,OAAO,UAAU,UAAU,YAAY,UAAU,UAAU,OACtD,UAAU,QACX;AAKN,QAAO;EACL,MAAM,WAAW,WAAW,OAAO,KAAK,QAAQ,WAAW,OAAO,OAAO,GAAG,KAAA;EAC5E,OAAO,WAAW,WAAW,QAAQ,KAAK,QAAQ,WAAW,OAAO,QAAQ,GAAG,KAAA;EAC/E,kBACE,WAAW,WAAW,oBAAoB,KACzC,QAAQ,WAAW,OAAO,oBAAoB,GAAG,KAAA;EACpD,SAAS,WAAW,WAAW,UAAU;EACzC,MAAM,WAAW,WAAW,OAAO;EACnC,QAAQ,WAAW,WAAW,SAAS;EACvC,cAAc,QAAQ,WAAW,OAAO,UAAU,GAAG,KAAA;EACrD,WAAW,QAAQ,WAAW,OAAO,OAAO,GAAG,KAAA;EAChD;;AAGH,SAAS,WAAW,OAAgC,KAAiC;AACnF,QAAO,OAAO,MAAM,SAAS,WAAY,MAAM,OAAkB,KAAA;;AAGnE,SAAS,WAAW,OAAgC,KAAiC;AACnF,QAAO,OAAO,MAAM,SAAS,WAAY,MAAM,OAAkB,KAAA"}
|
package/dist/oauth.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oauth.d.ts","sourceRoot":"","sources":["../src/oauth.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"oauth.d.ts","sourceRoot":"","sources":["../src/oauth.ts"],"names":[],"mappings":"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"}
|