@better-auth/infra 0.1.11 → 0.1.12
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.mts +237 -228
- package/dist/index.mjs +63 -8
- package/package.json +11 -11
package/dist/index.mjs
CHANGED
|
@@ -815,7 +815,10 @@ const getOrganizationTriggerInfo = (user) => {
|
|
|
815
815
|
const initTrackEvents = (options) => {
|
|
816
816
|
const $fetch = createFetch({
|
|
817
817
|
baseURL: options.apiUrl,
|
|
818
|
-
headers: {
|
|
818
|
+
headers: {
|
|
819
|
+
"user-agent": "better-auth",
|
|
820
|
+
"x-api-key": options.apiKey
|
|
821
|
+
}
|
|
819
822
|
});
|
|
820
823
|
const trackEvent = (data) => {
|
|
821
824
|
const track = async () => {
|
|
@@ -2678,13 +2681,16 @@ function isRecentlyIssued(payload) {
|
|
|
2678
2681
|
}
|
|
2679
2682
|
const jwtMiddleware = (options, schema, getJWT) => createAuthMiddleware(async (ctx) => {
|
|
2680
2683
|
const jwsFromHeader = getJWT ? await getJWT(ctx) : ctx.headers?.get("Authorization")?.split(" ")[1];
|
|
2681
|
-
if (!jwsFromHeader)
|
|
2684
|
+
if (!jwsFromHeader) {
|
|
2685
|
+
ctx.context.logger.warn("[Dash] JWT is missing from header");
|
|
2686
|
+
throw ctx.error("UNAUTHORIZED", { message: "Invalid API key" });
|
|
2687
|
+
}
|
|
2682
2688
|
const { payload } = await jwtVerify(jwsFromHeader, await getJWKs(options.apiUrl), { maxTokenAge: "5m" }).catch((e) => {
|
|
2683
|
-
ctx.context.logger.
|
|
2689
|
+
ctx.context.logger.warn("[Dash] JWT verification failed:", e);
|
|
2684
2690
|
throw ctx.error("UNAUTHORIZED", { message: "Invalid API key" });
|
|
2685
2691
|
});
|
|
2686
2692
|
if (!isRecentlyIssued(payload)) {
|
|
2687
|
-
|
|
2693
|
+
const { error, data } = await betterFetch("/api/auth/check-jti", {
|
|
2688
2694
|
baseURL: options.apiUrl,
|
|
2689
2695
|
method: "POST",
|
|
2690
2696
|
headers: { "x-api-key": options.apiKey },
|
|
@@ -2692,18 +2698,52 @@ const jwtMiddleware = (options, schema, getJWT) => createAuthMiddleware(async (c
|
|
|
2692
2698
|
jti: payload.jti,
|
|
2693
2699
|
expiresAt: payload.exp
|
|
2694
2700
|
}
|
|
2695
|
-
})
|
|
2701
|
+
});
|
|
2702
|
+
if (error || !data?.valid) {
|
|
2703
|
+
ctx.context.logger.warn("[Dash] JTI check failed with error", error, data?.valid);
|
|
2704
|
+
throw ctx.error("UNAUTHORIZED", { message: "Invalid API key" });
|
|
2705
|
+
}
|
|
2696
2706
|
}
|
|
2697
2707
|
const apiKeyHash = payload.apiKeyHash;
|
|
2698
|
-
if (typeof apiKeyHash !== "string" || !options.apiKey)
|
|
2699
|
-
|
|
2708
|
+
if (typeof apiKeyHash !== "string" || !options.apiKey) {
|
|
2709
|
+
ctx.context.logger.warn("[Dash] API key hash is missing or invalid", {
|
|
2710
|
+
apiKeyHash,
|
|
2711
|
+
apiKey: options.apiKey ? "present" : "missing"
|
|
2712
|
+
});
|
|
2713
|
+
throw ctx.error("UNAUTHORIZED", { message: "Invalid API key" });
|
|
2714
|
+
}
|
|
2715
|
+
const expectedHash = await hash(options.apiKey);
|
|
2716
|
+
if (apiKeyHash !== expectedHash) {
|
|
2717
|
+
ctx.context.logger.warn("[Dash] API key hash is invalid", apiKeyHash, expectedHash);
|
|
2718
|
+
throw ctx.error("UNAUTHORIZED", { message: "Invalid API key" });
|
|
2719
|
+
}
|
|
2700
2720
|
if (schema) {
|
|
2701
2721
|
const parsed = schema.safeParse(payload);
|
|
2702
|
-
if (!parsed.success)
|
|
2722
|
+
if (!parsed.success) {
|
|
2723
|
+
ctx.context.logger.warn("[Dash] JWT payload is invalid", parsed.error);
|
|
2724
|
+
throw ctx.error("UNAUTHORIZED", { message: "Invalid API key" });
|
|
2725
|
+
}
|
|
2703
2726
|
return { payload: parsed.data };
|
|
2704
2727
|
}
|
|
2705
2728
|
return { payload };
|
|
2706
2729
|
});
|
|
2730
|
+
/**
|
|
2731
|
+
* Lightweight JWT middleware for /dash/validate. Verifies JWT signature and
|
|
2732
|
+
* apiKeyHash only—no JTI check. Used during onboarding when the org doesn't
|
|
2733
|
+
* exist yet.
|
|
2734
|
+
*/
|
|
2735
|
+
const jwtValidateMiddleware = (options) => createAuthMiddleware(async (ctx) => {
|
|
2736
|
+
const jwsFromHeader = ctx.headers?.get("Authorization")?.split(" ")[1];
|
|
2737
|
+
if (!jwsFromHeader) throw ctx.error("UNAUTHORIZED", { message: "Invalid API key" });
|
|
2738
|
+
const { payload } = await jwtVerify(jwsFromHeader, await getJWKs(options.apiUrl), { maxTokenAge: "5m" }).catch((e) => {
|
|
2739
|
+
ctx.context.logger.error("[Dash] JWT verification failed:", e);
|
|
2740
|
+
throw ctx.error("UNAUTHORIZED", { message: "Invalid API key" });
|
|
2741
|
+
});
|
|
2742
|
+
const apiKeyHash = payload.apiKeyHash;
|
|
2743
|
+
if (typeof apiKeyHash !== "string" || !options.apiKey) throw ctx.error("UNAUTHORIZED", { message: "Invalid API key" });
|
|
2744
|
+
if (apiKeyHash !== await hash(options.apiKey)) throw ctx.error("UNAUTHORIZED", { message: "Invalid API key" });
|
|
2745
|
+
return { payload };
|
|
2746
|
+
});
|
|
2707
2747
|
|
|
2708
2748
|
//#endregion
|
|
2709
2749
|
//#region src/routes/config.ts
|
|
@@ -7419,6 +7459,20 @@ const generateBackupCodes = (options) => createAuthEndpoint("/dash/generate-back
|
|
|
7419
7459
|
return { backupCodes: newBackupCodes };
|
|
7420
7460
|
});
|
|
7421
7461
|
|
|
7462
|
+
//#endregion
|
|
7463
|
+
//#region src/routes/validate.ts
|
|
7464
|
+
/**
|
|
7465
|
+
* Lightweight endpoint to verify API key ownership during onboarding
|
|
7466
|
+
*/
|
|
7467
|
+
const getValidate = (options) => {
|
|
7468
|
+
return createAuthEndpoint("/dash/validate", {
|
|
7469
|
+
method: "GET",
|
|
7470
|
+
use: [jwtValidateMiddleware(options)]
|
|
7471
|
+
}, async () => {
|
|
7472
|
+
return { valid: true };
|
|
7473
|
+
});
|
|
7474
|
+
};
|
|
7475
|
+
|
|
7422
7476
|
//#endregion
|
|
7423
7477
|
//#region src/pow.ts
|
|
7424
7478
|
/** Default difficulty in bits (18 = ~500ms solve time) */
|
|
@@ -7922,6 +7976,7 @@ const dash = (options) => {
|
|
|
7922
7976
|
},
|
|
7923
7977
|
endpoints: {
|
|
7924
7978
|
getDashConfig: getConfig(opts),
|
|
7979
|
+
getDashValidate: getValidate(opts),
|
|
7925
7980
|
getDashUsers: getUsers(opts),
|
|
7926
7981
|
exportDashUsers: exportUsers(opts),
|
|
7927
7982
|
getOnlineUsersCount: getOnlineUsersCount(opts),
|
package/package.json
CHANGED
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@better-auth/infra",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.12",
|
|
4
4
|
"description": "Dashboard and analytics plugin for Better Auth",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.mjs",
|
|
7
7
|
"module": "dist/index.mjs",
|
|
8
8
|
"types": "dist/index.d.mts",
|
|
9
9
|
"sideEffects": false,
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsdown ",
|
|
12
|
+
"dev": "tsdown --watch",
|
|
13
|
+
"typecheck": "tsc --noEmit",
|
|
14
|
+
"test": "bun test",
|
|
15
|
+
"test:watch": "bun test --watch"
|
|
16
|
+
},
|
|
10
17
|
"exports": {
|
|
11
18
|
".": {
|
|
12
19
|
"types": "./dist/index.d.mts",
|
|
@@ -49,11 +56,11 @@
|
|
|
49
56
|
"homepage": "https://better-auth.com",
|
|
50
57
|
"devDependencies": {
|
|
51
58
|
"@types/bun": "latest",
|
|
52
|
-
"@types/node": "
|
|
59
|
+
"@types/node": "catalog:",
|
|
53
60
|
"better-auth": "beta",
|
|
54
61
|
"@better-auth/scim": "beta",
|
|
55
62
|
"tsdown": "^0.19.0-beta.2",
|
|
56
|
-
"typescript": "
|
|
63
|
+
"typescript": "catalog:",
|
|
57
64
|
"zod": "beta"
|
|
58
65
|
},
|
|
59
66
|
"dependencies": {
|
|
@@ -67,12 +74,5 @@
|
|
|
67
74
|
"zod": ">=4.1.12",
|
|
68
75
|
"@better-auth/core": ">=1.4.0",
|
|
69
76
|
"@better-auth/sso": ">=1.4.0"
|
|
70
|
-
},
|
|
71
|
-
"scripts": {
|
|
72
|
-
"build": "tsdown ",
|
|
73
|
-
"dev": "tsdown --watch",
|
|
74
|
-
"typecheck": "tsc --noEmit",
|
|
75
|
-
"test": "bun test",
|
|
76
|
-
"test:watch": "bun test --watch"
|
|
77
77
|
}
|
|
78
|
-
}
|
|
78
|
+
}
|