nestjs-slightly-better-auth 1.0.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/LICENSE +7 -0
- package/README.md +57 -0
- package/dist/admin.cjs +88 -0
- package/dist/admin.cjs.map +1 -0
- package/dist/admin.d.cts +14 -0
- package/dist/admin.d.cts.map +1 -0
- package/dist/admin.d.mts +14 -0
- package/dist/admin.d.mts.map +1 -0
- package/dist/admin.mjs +85 -0
- package/dist/admin.mjs.map +1 -0
- package/dist/api-key.cjs +163 -0
- package/dist/api-key.cjs.map +1 -0
- package/dist/api-key.d.cts +42 -0
- package/dist/api-key.d.cts.map +1 -0
- package/dist/api-key.d.mts +42 -0
- package/dist/api-key.d.mts.map +1 -0
- package/dist/api-key.mjs +159 -0
- package/dist/api-key.mjs.map +1 -0
- package/dist/auth-contracts-BBA1C1gj.d.cts +1635 -0
- package/dist/auth-contracts-BBA1C1gj.d.cts.map +1 -0
- package/dist/auth-contracts-tqsfBZ8B.d.mts +1635 -0
- package/dist/auth-contracts-tqsfBZ8B.d.mts.map +1 -0
- package/dist/auth-decorators-CwW5JY4y.cjs +1274 -0
- package/dist/auth-decorators-CwW5JY4y.cjs.map +1 -0
- package/dist/auth-decorators-DfAJbHar.mjs +849 -0
- package/dist/auth-decorators-DfAJbHar.mjs.map +1 -0
- package/dist/auth-errors-CQjfgjaO.mjs +283 -0
- package/dist/auth-errors-CQjfgjaO.mjs.map +1 -0
- package/dist/auth-errors-CsERBNWI.cjs +348 -0
- package/dist/auth-errors-CsERBNWI.cjs.map +1 -0
- package/dist/express.cjs +247 -0
- package/dist/express.cjs.map +1 -0
- package/dist/express.d.cts +37 -0
- package/dist/express.d.cts.map +1 -0
- package/dist/express.d.mts +37 -0
- package/dist/express.d.mts.map +1 -0
- package/dist/express.mjs +245 -0
- package/dist/express.mjs.map +1 -0
- package/dist/fastify.cjs +215 -0
- package/dist/fastify.cjs.map +1 -0
- package/dist/fastify.d.cts +28 -0
- package/dist/fastify.d.cts.map +1 -0
- package/dist/fastify.d.mts +28 -0
- package/dist/fastify.d.mts.map +1 -0
- package/dist/fastify.mjs +213 -0
- package/dist/fastify.mjs.map +1 -0
- package/dist/index.cjs +2634 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +2 -0
- package/dist/index.d.mts +2 -0
- package/dist/index.mjs +2556 -0
- package/dist/index.mjs.map +1 -0
- package/dist/organization.cjs +191 -0
- package/dist/organization.cjs.map +1 -0
- package/dist/organization.d.cts +40 -0
- package/dist/organization.d.cts.map +1 -0
- package/dist/organization.d.mts +40 -0
- package/dist/organization.d.mts.map +1 -0
- package/dist/organization.mjs +177 -0
- package/dist/organization.mjs.map +1 -0
- package/dist/platform.cjs +393 -0
- package/dist/platform.cjs.map +1 -0
- package/dist/platform.d.cts +43 -0
- package/dist/platform.d.cts.map +1 -0
- package/dist/platform.d.mts +43 -0
- package/dist/platform.d.mts.map +1 -0
- package/dist/platform.mjs +385 -0
- package/dist/platform.mjs.map +1 -0
- package/dist/plugin.cjs +312 -0
- package/dist/plugin.cjs.map +1 -0
- package/dist/plugin.d.cts +26 -0
- package/dist/plugin.d.cts.map +1 -0
- package/dist/plugin.d.mts +26 -0
- package/dist/plugin.d.mts.map +1 -0
- package/dist/plugin.mjs +310 -0
- package/dist/plugin.mjs.map +1 -0
- package/package.json +186 -0
package/dist/api-key.mjs
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { n as BetterAuthConfigurationError, r as BetterAuthInfrastructureError, t as AuthFailures, u as normalizeThrown } from "./auth-errors-CQjfgjaO.mjs";
|
|
2
|
+
import { F as authenticated, P as absent, R as rejected, u as Require } from "./auth-decorators-DfAJbHar.mjs";
|
|
3
|
+
import { role } from "better-auth/plugins/access";
|
|
4
|
+
//#region src/api-key.ts
|
|
5
|
+
const API_KEY_PRINCIPAL_KIND = "api-key";
|
|
6
|
+
function apiKeyPrincipal(options = {}) {
|
|
7
|
+
const header = options.header ?? "x-api-key";
|
|
8
|
+
const slowMs = typeof options.outageProbe === "object" ? options.outageProbe.slowMs ?? 500 : 500;
|
|
9
|
+
if (!header.trim() || slowMs !== false && (!Number.isFinite(slowMs) || slowMs < 0)) throw new BetterAuthConfigurationError("INVALID_API_KEY_OPTIONS", "API-key header must be nonempty and slowMs must be finite and nonnegative.");
|
|
10
|
+
const verificationMemo = Symbol("api-key-verification");
|
|
11
|
+
const probes = /* @__PURE__ */ new WeakMap();
|
|
12
|
+
async function probe(auth) {
|
|
13
|
+
const previous = probes.get(auth.instance);
|
|
14
|
+
if (previous && (previous.pending || Date.now() - previous.at < 1e3)) return previous.result;
|
|
15
|
+
const result = (async () => {
|
|
16
|
+
const context = await auth.context();
|
|
17
|
+
const where = [{
|
|
18
|
+
field: "key",
|
|
19
|
+
value: crypto.randomUUID()
|
|
20
|
+
}];
|
|
21
|
+
await context.adapter.findOne({
|
|
22
|
+
model: "apikey",
|
|
23
|
+
where
|
|
24
|
+
});
|
|
25
|
+
await context.adapter.updateMany({
|
|
26
|
+
model: "apikey",
|
|
27
|
+
where,
|
|
28
|
+
update: { updatedAt: /* @__PURE__ */ new Date() }
|
|
29
|
+
});
|
|
30
|
+
})();
|
|
31
|
+
const state = {
|
|
32
|
+
at: Date.now(),
|
|
33
|
+
pending: true,
|
|
34
|
+
result
|
|
35
|
+
};
|
|
36
|
+
probes.set(auth.instance, state);
|
|
37
|
+
result.then(() => {
|
|
38
|
+
state.pending = false;
|
|
39
|
+
}, () => {
|
|
40
|
+
state.pending = false;
|
|
41
|
+
});
|
|
42
|
+
return result;
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
id: "better-auth:api-key",
|
|
46
|
+
kinds: [API_KEY_PRINCIPAL_KIND],
|
|
47
|
+
acceptance: options.acceptance ?? "explicit",
|
|
48
|
+
delegates: true,
|
|
49
|
+
credentialHeaders: [header],
|
|
50
|
+
effects: {
|
|
51
|
+
consumesQuota: true,
|
|
52
|
+
writes: true
|
|
53
|
+
},
|
|
54
|
+
requires: { plugins: ["api-key"] },
|
|
55
|
+
appliesTo: (request) => request.headers.has(header),
|
|
56
|
+
async resolve(request) {
|
|
57
|
+
if (!request.headers.has(header)) return absent();
|
|
58
|
+
return request.memo(verificationMemo, async () => {
|
|
59
|
+
const key = request.headers.get(header);
|
|
60
|
+
const headers = new Headers();
|
|
61
|
+
for (const name of [
|
|
62
|
+
"host",
|
|
63
|
+
"x-forwarded-host",
|
|
64
|
+
"x-forwarded-proto"
|
|
65
|
+
]) {
|
|
66
|
+
const value = request.headers.get(name);
|
|
67
|
+
if (value !== null) headers.set(name, value);
|
|
68
|
+
}
|
|
69
|
+
const started = performance.now();
|
|
70
|
+
try {
|
|
71
|
+
const result = await request.auth.run({
|
|
72
|
+
cookies: request.cookies,
|
|
73
|
+
inbound: () => request.headers,
|
|
74
|
+
internal: true
|
|
75
|
+
}, () => request.auth.api.verifyApiKey({
|
|
76
|
+
body: {
|
|
77
|
+
key,
|
|
78
|
+
...options.configId === void 0 ? {} : { configId: options.configId }
|
|
79
|
+
},
|
|
80
|
+
headers
|
|
81
|
+
}));
|
|
82
|
+
if (result.valid) {
|
|
83
|
+
const verified = result.key;
|
|
84
|
+
if (!verified || typeof verified.id !== "string" || typeof verified.referenceId !== "string") throw new BetterAuthInfrastructureError(/* @__PURE__ */ new Error("Malformed API-key verification result"));
|
|
85
|
+
const configId = verified.configId ?? null;
|
|
86
|
+
const references = typeof options.references === "function" ? options.references({ configId }) : options.references ?? "user";
|
|
87
|
+
const permissions = verified.permissions ?? null;
|
|
88
|
+
const grant = role(permissions ?? {});
|
|
89
|
+
return authenticated({
|
|
90
|
+
kind: API_KEY_PRINCIPAL_KIND,
|
|
91
|
+
source: "better-auth:api-key",
|
|
92
|
+
keyId: verified.id,
|
|
93
|
+
configId,
|
|
94
|
+
referenceId: verified.referenceId,
|
|
95
|
+
userId: references === "user" ? verified.referenceId : null,
|
|
96
|
+
organizationId: references === "organization" ? verified.referenceId : null,
|
|
97
|
+
permissions,
|
|
98
|
+
delegation: {
|
|
99
|
+
description: "api-key permissions",
|
|
100
|
+
allows: (requested) => grant.authorize(requested).success
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
const code = result.error?.code;
|
|
105
|
+
if (code === "RATE_LIMITED" || code === "USAGE_EXCEEDED") {
|
|
106
|
+
const retry = result.error?.details?.tryAgainIn;
|
|
107
|
+
return rejected(AuthFailures.rejected({
|
|
108
|
+
status: 429,
|
|
109
|
+
reason: code,
|
|
110
|
+
...code === "RATE_LIMITED" && typeof retry === "number" ? { retryAfterSeconds: retry / 1e3 } : {}
|
|
111
|
+
}));
|
|
112
|
+
}
|
|
113
|
+
if (code === "INVALID_API_KEY" && options.outageProbe !== false) {
|
|
114
|
+
if (slowMs !== false && performance.now() - started > slowMs) throw new BetterAuthInfrastructureError(/* @__PURE__ */ new Error("API-key verification exceeded the outage threshold"));
|
|
115
|
+
await probe(request.auth);
|
|
116
|
+
}
|
|
117
|
+
if (code === "INVALID_API_KEY" || code === "KEY_NOT_FOUND" || code === "KEY_DISABLED" || code === "KEY_EXPIRED") return rejected(AuthFailures.rejected({
|
|
118
|
+
status: 401,
|
|
119
|
+
reason: code
|
|
120
|
+
}));
|
|
121
|
+
throw new BetterAuthInfrastructureError(/* @__PURE__ */ new Error(`Unexpected API-key verification error: ${code ?? "missing code"}`));
|
|
122
|
+
} catch (error) {
|
|
123
|
+
const failure = normalizeThrown(error, "source", "better-auth:api-key", [key]);
|
|
124
|
+
if ("sessionLoss" in failure) throw new BetterAuthInfrastructureError(error, { secrets: [key] });
|
|
125
|
+
return rejected(failure);
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
const apiKeyPermissionPolicy = {
|
|
132
|
+
id: "better-auth:api-key/permission",
|
|
133
|
+
requires: {
|
|
134
|
+
plugins: ["api-key"],
|
|
135
|
+
principals: [API_KEY_PRINCIPAL_KIND]
|
|
136
|
+
},
|
|
137
|
+
validate(permissions) {
|
|
138
|
+
if (!Object.keys(permissions).length || Object.values(permissions).some((actions) => !Array.isArray(actions) || !actions.length)) throw new BetterAuthConfigurationError("EMPTY_PERMISSIONS", "API-key permissions must contain a resource and actions.");
|
|
139
|
+
},
|
|
140
|
+
evaluate(permissions, context) {
|
|
141
|
+
return context.principal.delegation.allows(permissions) ? { effect: "allow" } : {
|
|
142
|
+
effect: "deny",
|
|
143
|
+
reason: "MISSING_PERMISSION"
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
function apiKeyPermission(permissions) {
|
|
148
|
+
return {
|
|
149
|
+
policy: apiKeyPermissionPolicy,
|
|
150
|
+
params: permissions
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
function RequireApiKeyPermission(permissions) {
|
|
154
|
+
return Require(apiKeyPermission(permissions));
|
|
155
|
+
}
|
|
156
|
+
//#endregion
|
|
157
|
+
export { API_KEY_PRINCIPAL_KIND, RequireApiKeyPermission, apiKeyPermission, apiKeyPrincipal };
|
|
158
|
+
|
|
159
|
+
//# sourceMappingURL=api-key.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-key.mjs","names":[],"sources":["../src/api-key.ts"],"sourcesContent":["import { role } from \"better-auth/plugins/access\";\nimport type {\n AuthHandle,\n AuthPrincipalBase,\n AuthorizationPolicy,\n PrincipalDelegation,\n PrincipalSource,\n Requirement,\n} from \"./auth-contracts.js\";\nimport { Require } from \"./auth-decorators.js\";\nimport {\n AuthFailures,\n BetterAuthConfigurationError,\n BetterAuthInfrastructureError,\n normalizeThrown,\n} from \"./auth-errors.js\";\nimport { absent, authenticated, rejected } from \"./principal-resolver.js\";\n\nexport const API_KEY_PRINCIPAL_KIND = \"api-key\" as const;\nexport interface ApiKeyPrincipal extends AuthPrincipalBase {\n readonly kind: \"api-key\";\n readonly keyId: string;\n readonly configId: string | null;\n readonly referenceId: string;\n readonly userId: string | null;\n readonly organizationId: string | null;\n readonly permissions: Readonly<Record<string, readonly string[]>> | null;\n readonly delegation: PrincipalDelegation;\n}\n// The public module identity survives declaration bundling in both output formats.\ndeclare module \"nestjs-slightly-better-auth\" {\n interface PrincipalKinds {\n \"api-key\": ApiKeyPrincipal;\n }\n}\nexport interface ApiKeyPrincipalOptions {\n header?: string;\n configId?: string;\n references?:\n | \"user\"\n | \"organization\"\n | ((key: { readonly configId: string | null }) => \"user\" | \"organization\");\n /**\n * Default true: slow INVALID_API_KEY results (>500 ms) throw infrastructure errors,\n * then fast failures share one read/no-op-write probe per second per instance.\n * false disables both checks; { slowMs: false } keeps only the probe.\n * Set slowMs below pool lock/statement timeouts and above custom hashing costs.\n * Fast failures confined to one row, or secondary storage without database fallback,\n * may still look like invalid keys. A statement-level trigger can observe the zero-row write.\n */\n outageProbe?: boolean | { readonly slowMs?: number | false };\n acceptance?: \"default\" | \"explicit\";\n}\ninterface VerifiedKey {\n id: string;\n configId?: string | null;\n referenceId: string;\n permissions?: Record<string, readonly string[]> | null;\n}\ninterface Verification {\n valid: boolean;\n key?: VerifiedKey | null;\n error?: { code?: string; details?: { tryAgainIn?: number } } | null;\n}\ninterface KeyApi {\n verifyApiKey(input: {\n body: { key: string; configId?: string };\n headers: Headers;\n }): Promise<Verification>;\n}\nexport function apiKeyPrincipal(\n options: ApiKeyPrincipalOptions = {},\n): PrincipalSource<ApiKeyPrincipal> {\n const header = options.header ?? \"x-api-key\";\n const slowMs =\n typeof options.outageProbe === \"object\"\n ? (options.outageProbe.slowMs ?? 500)\n : 500;\n if (\n !header.trim() ||\n (slowMs !== false && (!Number.isFinite(slowMs) || slowMs < 0))\n ) {\n throw new BetterAuthConfigurationError(\n \"INVALID_API_KEY_OPTIONS\",\n \"API-key header must be nonempty and slowMs must be finite and nonnegative.\",\n );\n }\n const verificationMemo = Symbol(\"api-key-verification\");\n const probes = new WeakMap<\n object,\n { at: number; pending: boolean; result: Promise<void> }\n >();\n async function probe(auth: AuthHandle): Promise<void> {\n const previous = probes.get(auth.instance);\n if (previous && (previous.pending || Date.now() - previous.at < 1000)) {\n return previous.result;\n }\n const result = (async () => {\n const context = await auth.context();\n // The logical key column is string-valued for default, UUID and serial IDs.\n const where = [{ field: \"key\", value: crypto.randomUUID() }];\n await context.adapter.findOne({ model: \"apikey\", where });\n await context.adapter.updateMany({\n model: \"apikey\",\n where,\n update: { updatedAt: new Date() },\n });\n })();\n const state = { at: Date.now(), pending: true, result };\n probes.set(auth.instance, state);\n void result.then(\n () => {\n state.pending = false;\n },\n () => {\n state.pending = false;\n },\n );\n return result;\n }\n return {\n id: \"better-auth:api-key\",\n kinds: [API_KEY_PRINCIPAL_KIND],\n acceptance: options.acceptance ?? \"explicit\",\n delegates: true,\n credentialHeaders: [header],\n effects: { consumesQuota: true, writes: true },\n requires: { plugins: [\"api-key\"] },\n appliesTo: (request) => request.headers.has(header),\n async resolve(request) {\n if (!request.headers.has(header)) {\n return absent();\n }\n return request.memo(verificationMemo, async () => {\n const key = request.headers.get(header)!;\n const headers = new Headers();\n for (const name of [\"host\", \"x-forwarded-host\", \"x-forwarded-proto\"]) {\n const value = request.headers.get(name);\n if (value !== null) {\n headers.set(name, value);\n }\n }\n const started = performance.now();\n try {\n const result = await request.auth.run(\n {\n cookies: request.cookies,\n inbound: () => request.headers,\n internal: true,\n },\n () =>\n (request.auth.api as unknown as KeyApi).verifyApiKey({\n body: {\n key,\n ...(options.configId === undefined\n ? {}\n : { configId: options.configId }),\n },\n headers,\n }),\n );\n if (result.valid) {\n const verified = result.key;\n if (\n !verified ||\n typeof verified.id !== \"string\" ||\n typeof verified.referenceId !== \"string\"\n ) {\n throw new BetterAuthInfrastructureError(\n new Error(\"Malformed API-key verification result\"),\n );\n }\n const configId = verified.configId ?? null;\n const references =\n typeof options.references === \"function\"\n ? options.references({ configId })\n : (options.references ?? \"user\");\n const permissions = verified.permissions ?? null;\n const grant = role(permissions ?? {});\n return authenticated({\n kind: API_KEY_PRINCIPAL_KIND,\n source: \"better-auth:api-key\",\n keyId: verified.id,\n configId,\n referenceId: verified.referenceId,\n userId: references === \"user\" ? verified.referenceId : null,\n organizationId:\n references === \"organization\" ? verified.referenceId : null,\n permissions,\n delegation: {\n description: \"api-key permissions\",\n allows: (requested) => grant.authorize(requested).success,\n },\n });\n }\n const code = result.error?.code;\n if (code === \"RATE_LIMITED\" || code === \"USAGE_EXCEEDED\") {\n const retry = result.error?.details?.tryAgainIn;\n return rejected(\n AuthFailures.rejected({\n status: 429,\n reason: code,\n ...(code === \"RATE_LIMITED\" && typeof retry === \"number\"\n ? { retryAfterSeconds: retry / 1000 }\n : {}),\n }),\n );\n }\n if (code === \"INVALID_API_KEY\" && options.outageProbe !== false) {\n if (slowMs !== false && performance.now() - started > slowMs) {\n throw new BetterAuthInfrastructureError(\n new Error(\"API-key verification exceeded the outage threshold\"),\n );\n }\n await probe(request.auth);\n }\n if (\n code === \"INVALID_API_KEY\" ||\n code === \"KEY_NOT_FOUND\" ||\n code === \"KEY_DISABLED\" ||\n code === \"KEY_EXPIRED\"\n ) {\n return rejected(\n AuthFailures.rejected({ status: 401, reason: code }),\n );\n }\n throw new BetterAuthInfrastructureError(\n new Error(\n `Unexpected API-key verification error: ${code ?? \"missing code\"}`,\n ),\n );\n } catch (error) {\n const failure = normalizeThrown(\n error,\n \"source\",\n \"better-auth:api-key\",\n [key],\n );\n if (\"sessionLoss\" in failure) {\n throw new BetterAuthInfrastructureError(error, { secrets: [key] });\n }\n return rejected(failure);\n }\n });\n },\n };\n}\nconst apiKeyPermissionPolicy: AuthorizationPolicy<\n Record<string, string[]>,\n ApiKeyPrincipal\n> = {\n id: \"better-auth:api-key/permission\",\n requires: { plugins: [\"api-key\"], principals: [API_KEY_PRINCIPAL_KIND] },\n validate(permissions) {\n if (\n !Object.keys(permissions).length ||\n Object.values(permissions).some(\n (actions) => !Array.isArray(actions) || !actions.length,\n )\n ) {\n throw new BetterAuthConfigurationError(\n \"EMPTY_PERMISSIONS\",\n \"API-key permissions must contain a resource and actions.\",\n );\n }\n },\n evaluate(permissions, context) {\n return context.principal.delegation.allows(permissions)\n ? { effect: \"allow\" }\n : { effect: \"deny\", reason: \"MISSING_PERMISSION\" };\n },\n};\nexport function apiKeyPermission(\n permissions: Record<string, string[]>,\n): Requirement<Record<string, string[]>> {\n return { policy: apiKeyPermissionPolicy, params: permissions };\n}\nexport function RequireApiKeyPermission(\n permissions: Record<string, string[]>,\n): ClassDecorator & MethodDecorator {\n return Require(apiKeyPermission(permissions));\n}\n"],"mappings":"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"}
|