@strapi-community/plugin-better-auth-dashboard 1.0.0-alpha.1

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.
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ const PLUGIN_ID = "better-auth-dashboard";
3
+ function captureApp(app) {
4
+ window.__betterAuthDashApp = app;
5
+ }
6
+ function getMediaLibraryComponent() {
7
+ return window.__betterAuthDashApp?.library?.components?.["media-library"] ?? null;
8
+ }
9
+ const index = {
10
+ register(app) {
11
+ captureApp(app);
12
+ app.addMenuLink({
13
+ to: `/plugins/${PLUGIN_ID}`,
14
+ icon: () => null,
15
+ intlLabel: {
16
+ id: `${PLUGIN_ID}.plugin.name`,
17
+ defaultMessage: "Auth Dashboard"
18
+ },
19
+ Component: async () => Promise.resolve().then(() => require("./Root-Bl4iPGDu.js"))
20
+ });
21
+ },
22
+ bootstrap() {
23
+ }
24
+ };
25
+ exports.getMediaLibraryComponent = getMediaLibraryComponent;
26
+ exports.index = index;
@@ -0,0 +1,27 @@
1
+ const PLUGIN_ID = "better-auth-dashboard";
2
+ function captureApp(app) {
3
+ window.__betterAuthDashApp = app;
4
+ }
5
+ function getMediaLibraryComponent() {
6
+ return window.__betterAuthDashApp?.library?.components?.["media-library"] ?? null;
7
+ }
8
+ const index = {
9
+ register(app) {
10
+ captureApp(app);
11
+ app.addMenuLink({
12
+ to: `/plugins/${PLUGIN_ID}`,
13
+ icon: () => null,
14
+ intlLabel: {
15
+ id: `${PLUGIN_ID}.plugin.name`,
16
+ defaultMessage: "Auth Dashboard"
17
+ },
18
+ Component: async () => import("./Root-hwPhIfaT.mjs")
19
+ });
20
+ },
21
+ bootstrap() {
22
+ }
23
+ };
24
+ export {
25
+ getMediaLibraryComponent as g,
26
+ index as i
27
+ };
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
3
+ const index = require("./index-A9PUvldu.js");
4
+ exports.default = index.index;
@@ -0,0 +1,4 @@
1
+ import { i } from "./index-Cvcysa5M.mjs";
2
+ export {
3
+ i as default
4
+ };
@@ -0,0 +1,138 @@
1
+ "use strict";
2
+ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
3
+ const utils = require("@strapi/utils");
4
+ const DASHBOARD_API_KEY = process.env.BETTER_AUTH_DASHBOARD_SECRET || "strapi-internal-dashboard-key";
5
+ const DASH_CONTEXT_HEADER = "x-dash-context";
6
+ async function hashApiKey(value) {
7
+ const data = new TextEncoder().encode(value);
8
+ const buf = await crypto.subtle.digest("SHA-256", data);
9
+ return Array.from(new Uint8Array(buf)).map((b) => b.toString(16).padStart(2, "0")).join("");
10
+ }
11
+ const proxyController = () => ({
12
+ async handleAuthRequest(ctx) {
13
+ const auth = strapi.service("plugin::better-auth.auth-service").getAuth();
14
+ if (!auth)
15
+ throw new utils.errors.ApplicationError("No Better Auth config file found");
16
+ if (!auth.api.signJWT) {
17
+ throw new utils.errors.ApplicationError(
18
+ "[@strapi-community/plugin-better-auth-dashboard] The better-auth JWT plugin is required. Add jwt() from 'better-auth/plugins' to your better-auth configuration."
19
+ );
20
+ }
21
+ const contextHeader = ctx.request.headers[DASH_CONTEXT_HEADER];
22
+ let extra = {};
23
+ if (typeof contextHeader === "string" && contextHeader.length > 0) {
24
+ try {
25
+ const decoded = Buffer.from(contextHeader, "base64").toString("utf8");
26
+ const parsed = JSON.parse(decoded);
27
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
28
+ extra = parsed;
29
+ }
30
+ } catch {
31
+ }
32
+ }
33
+ const apiKeyHash = await hashApiKey(DASHBOARD_API_KEY);
34
+ const { token } = await auth.api.signJWT({
35
+ body: {
36
+ payload: { iat: Math.floor(Date.now() / 1e3), apiKeyHash, ...extra },
37
+ overrideOptions: { jwt: { expirationTime: "5m" } }
38
+ }
39
+ });
40
+ console.log("Generated JWT with payload:", { token });
41
+ const url = new URL(
42
+ ctx.request.url,
43
+ `${ctx.request.protocol}://${ctx.request.host}`
44
+ );
45
+ const betterAuthPath = ctx.params.path || "";
46
+ url.pathname = `/api/auth/${betterAuthPath}`;
47
+ const headers = new Headers();
48
+ Object.entries(ctx.request.headers).forEach(([key, value]) => {
49
+ if (value) {
50
+ headers.set(key, Array.isArray(value) ? value[0] : String(value));
51
+ }
52
+ });
53
+ headers.set("Authorization", `Bearer ${token}`);
54
+ const hasBody = ctx.request.method !== "GET" && ctx.request.method !== "HEAD";
55
+ const request = new Request(url.toString(), {
56
+ method: ctx.request.method,
57
+ headers,
58
+ body: hasBody ? JSON.stringify(ctx.request.body) : void 0
59
+ });
60
+ const response = await auth.handler(request);
61
+ ctx.status = response.status;
62
+ response.headers.forEach((value, key) => {
63
+ ctx.set(key, value);
64
+ });
65
+ const contentType = response.headers.get("content-type");
66
+ if (contentType?.includes("application/json")) {
67
+ ctx.body = await response.json();
68
+ } else if (contentType?.includes("text/")) {
69
+ ctx.body = await response.text();
70
+ } else {
71
+ ctx.body = await response.text();
72
+ }
73
+ }
74
+ });
75
+ const controllers = {
76
+ "auth-controller": proxyController
77
+ };
78
+ const adminRoutes = () => ({
79
+ type: "admin",
80
+ routes: [
81
+ {
82
+ method: "GET",
83
+ path: "/auth/:path*",
84
+ handler: "auth-controller.handleAuthRequest",
85
+ config: {
86
+ policies: [],
87
+ prefix: "",
88
+ auth: false
89
+ }
90
+ },
91
+ {
92
+ method: "POST",
93
+ path: "/auth/:path*",
94
+ handler: "auth-controller.handleAuthRequest",
95
+ config: {
96
+ policies: [],
97
+ auth: false,
98
+ prefix: ""
99
+ }
100
+ },
101
+ {
102
+ method: "PUT",
103
+ path: "/auth/:path*",
104
+ handler: "auth-controller.handleAuthRequest",
105
+ config: {
106
+ policies: [],
107
+ auth: false,
108
+ prefix: ""
109
+ }
110
+ },
111
+ {
112
+ method: "PATCH",
113
+ path: "/auth/:path*",
114
+ handler: "auth-controller.handleAuthRequest",
115
+ config: {
116
+ policies: [],
117
+ auth: false,
118
+ prefix: ""
119
+ }
120
+ },
121
+ {
122
+ method: "DELETE",
123
+ path: "/auth/:path*",
124
+ handler: "auth-controller.handleAuthRequest",
125
+ config: {
126
+ policies: [],
127
+ auth: false,
128
+ prefix: ""
129
+ }
130
+ }
131
+ ]
132
+ });
133
+ const routes = { admin: adminRoutes };
134
+ const index = {
135
+ controllers,
136
+ routes
137
+ };
138
+ exports.default = index;
@@ -0,0 +1,138 @@
1
+ import { errors } from "@strapi/utils";
2
+ const DASHBOARD_API_KEY = process.env.BETTER_AUTH_DASHBOARD_SECRET || "strapi-internal-dashboard-key";
3
+ const DASH_CONTEXT_HEADER = "x-dash-context";
4
+ async function hashApiKey(value) {
5
+ const data = new TextEncoder().encode(value);
6
+ const buf = await crypto.subtle.digest("SHA-256", data);
7
+ return Array.from(new Uint8Array(buf)).map((b) => b.toString(16).padStart(2, "0")).join("");
8
+ }
9
+ const proxyController = () => ({
10
+ async handleAuthRequest(ctx) {
11
+ const auth = strapi.service("plugin::better-auth.auth-service").getAuth();
12
+ if (!auth)
13
+ throw new errors.ApplicationError("No Better Auth config file found");
14
+ if (!auth.api.signJWT) {
15
+ throw new errors.ApplicationError(
16
+ "[@strapi-community/plugin-better-auth-dashboard] The better-auth JWT plugin is required. Add jwt() from 'better-auth/plugins' to your better-auth configuration."
17
+ );
18
+ }
19
+ const contextHeader = ctx.request.headers[DASH_CONTEXT_HEADER];
20
+ let extra = {};
21
+ if (typeof contextHeader === "string" && contextHeader.length > 0) {
22
+ try {
23
+ const decoded = Buffer.from(contextHeader, "base64").toString("utf8");
24
+ const parsed = JSON.parse(decoded);
25
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
26
+ extra = parsed;
27
+ }
28
+ } catch {
29
+ }
30
+ }
31
+ const apiKeyHash = await hashApiKey(DASHBOARD_API_KEY);
32
+ const { token } = await auth.api.signJWT({
33
+ body: {
34
+ payload: { iat: Math.floor(Date.now() / 1e3), apiKeyHash, ...extra },
35
+ overrideOptions: { jwt: { expirationTime: "5m" } }
36
+ }
37
+ });
38
+ console.log("Generated JWT with payload:", { token });
39
+ const url = new URL(
40
+ ctx.request.url,
41
+ `${ctx.request.protocol}://${ctx.request.host}`
42
+ );
43
+ const betterAuthPath = ctx.params.path || "";
44
+ url.pathname = `/api/auth/${betterAuthPath}`;
45
+ const headers = new Headers();
46
+ Object.entries(ctx.request.headers).forEach(([key, value]) => {
47
+ if (value) {
48
+ headers.set(key, Array.isArray(value) ? value[0] : String(value));
49
+ }
50
+ });
51
+ headers.set("Authorization", `Bearer ${token}`);
52
+ const hasBody = ctx.request.method !== "GET" && ctx.request.method !== "HEAD";
53
+ const request = new Request(url.toString(), {
54
+ method: ctx.request.method,
55
+ headers,
56
+ body: hasBody ? JSON.stringify(ctx.request.body) : void 0
57
+ });
58
+ const response = await auth.handler(request);
59
+ ctx.status = response.status;
60
+ response.headers.forEach((value, key) => {
61
+ ctx.set(key, value);
62
+ });
63
+ const contentType = response.headers.get("content-type");
64
+ if (contentType?.includes("application/json")) {
65
+ ctx.body = await response.json();
66
+ } else if (contentType?.includes("text/")) {
67
+ ctx.body = await response.text();
68
+ } else {
69
+ ctx.body = await response.text();
70
+ }
71
+ }
72
+ });
73
+ const controllers = {
74
+ "auth-controller": proxyController
75
+ };
76
+ const adminRoutes = () => ({
77
+ type: "admin",
78
+ routes: [
79
+ {
80
+ method: "GET",
81
+ path: "/auth/:path*",
82
+ handler: "auth-controller.handleAuthRequest",
83
+ config: {
84
+ policies: [],
85
+ prefix: "",
86
+ auth: false
87
+ }
88
+ },
89
+ {
90
+ method: "POST",
91
+ path: "/auth/:path*",
92
+ handler: "auth-controller.handleAuthRequest",
93
+ config: {
94
+ policies: [],
95
+ auth: false,
96
+ prefix: ""
97
+ }
98
+ },
99
+ {
100
+ method: "PUT",
101
+ path: "/auth/:path*",
102
+ handler: "auth-controller.handleAuthRequest",
103
+ config: {
104
+ policies: [],
105
+ auth: false,
106
+ prefix: ""
107
+ }
108
+ },
109
+ {
110
+ method: "PATCH",
111
+ path: "/auth/:path*",
112
+ handler: "auth-controller.handleAuthRequest",
113
+ config: {
114
+ policies: [],
115
+ auth: false,
116
+ prefix: ""
117
+ }
118
+ },
119
+ {
120
+ method: "DELETE",
121
+ path: "/auth/:path*",
122
+ handler: "auth-controller.handleAuthRequest",
123
+ config: {
124
+ policies: [],
125
+ auth: false,
126
+ prefix: ""
127
+ }
128
+ }
129
+ ]
130
+ });
131
+ const routes = { admin: adminRoutes };
132
+ const index = {
133
+ controllers,
134
+ routes
135
+ };
136
+ export {
137
+ index as default
138
+ };
package/package.json ADDED
@@ -0,0 +1,84 @@
1
+ {
2
+ "name": "@strapi-community/plugin-better-auth-dashboard",
3
+ "version": "1.0.0-alpha.1",
4
+ "description": "Better Auth dashboard for the Strapi admin panel",
5
+ "keywords": [
6
+ "strapi",
7
+ "plugin",
8
+ "better-auth",
9
+ "dashboard"
10
+ ],
11
+ "license": "MIT",
12
+ "author": {
13
+ "name": "Boaz Poolman",
14
+ "email": "boaz@pluginpal.io",
15
+ "url": "https://github.com/boazpoolman"
16
+ },
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "git+https://github.com/strapi-community/plugin-better-auth.git",
20
+ "directory": "packages/plugin-better-auth-dashboard"
21
+ },
22
+ "type": "commonjs",
23
+ "exports": {
24
+ "./package.json": "./package.json",
25
+ "./strapi-admin": {
26
+ "source": "./admin/src/index.ts",
27
+ "import": "./dist/admin/index.mjs",
28
+ "require": "./dist/admin/index.js",
29
+ "default": "./dist/admin/index.js"
30
+ },
31
+ "./strapi-server": {
32
+ "source": "./server/src/index.ts",
33
+ "import": "./dist/server/index.mjs",
34
+ "require": "./dist/server/index.js",
35
+ "default": "./dist/server/index.js"
36
+ }
37
+ },
38
+ "files": [
39
+ "dist"
40
+ ],
41
+ "devDependencies": {
42
+ "@biomejs/biome": "^2.3.11",
43
+ "@playwright/test": "^1.49.0",
44
+ "@strapi/sdk-plugin": "^6.0.0",
45
+ "@strapi/strapi": "5.45.0",
46
+ "@strapi/typescript-utils": "5.45.0",
47
+ "@types/koa": "^3.0.1",
48
+ "@types/node": "^22",
49
+ "@types/react": "^18.0.0",
50
+ "@types/styled-components": "^5.1.36",
51
+ "typescript": "^5.9.3"
52
+ },
53
+ "peerDependencies": {
54
+ "@better-auth/infra": "^0.2.6",
55
+ "@strapi/design-system": "^2.0.0",
56
+ "@strapi/icons": "^2.0.0",
57
+ "@strapi/strapi": "^5.45.0",
58
+ "@strapi/types": "^5.45.0",
59
+ "@strapi/utils": "^5.45.0",
60
+ "better-auth": ">=1.4.0 <2",
61
+ "react": "^18.0.0",
62
+ "react-dom": "^18.0.0",
63
+ "react-intl": "^6.0.0 || ^7.0.0",
64
+ "react-query": "^3.0.0",
65
+ "styled-components": "^6.0.0",
66
+ "@strapi-community/plugin-better-auth": "^1.0.0-beta.6"
67
+ },
68
+ "strapi": {
69
+ "kind": "plugin",
70
+ "name": "better-auth-dashboard",
71
+ "displayName": "Better Auth Dashboard",
72
+ "description": "Better Auth dashboard for the Strapi admin panel"
73
+ },
74
+ "scripts": {
75
+ "build": "strapi-plugin build",
76
+ "watch": "strapi-plugin watch",
77
+ "dev": "strapi-plugin watch",
78
+ "verify": "strapi-plugin verify",
79
+ "test:ts:server": "cd server && tsc --noEmit",
80
+ "test:ts:admin": "cd admin && tsc --noEmit",
81
+ "check-types": "pnpm run test:ts:server && pnpm run test:ts:admin",
82
+ "lint": "biome check --fix"
83
+ }
84
+ }