@mastra/auth-better-auth 0.0.0-agent-chat-ui-20260305212602
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/CHANGELOG.md +124 -0
- package/LICENSE.md +30 -0
- package/README.md +107 -0
- package/dist/index.cjs +247 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +159 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +245 -0
- package/dist/index.js.map +1 -0
- package/package.json +63 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# @mastra/auth-better-auth
|
|
2
|
+
|
|
3
|
+
## 0.0.0-agent-chat-ui-20260305212602
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [[`41e48c1`](https://github.com/mastra-ai/mastra/commit/41e48c198eee846478e60c02ec432c19d322a517), [`82469d3`](https://github.com/mastra-ai/mastra/commit/82469d3135d5a49dd8dc8feec0ff398b4e0225a0), [`33e2fd5`](https://github.com/mastra-ai/mastra/commit/33e2fd5088f83666df17401e2da68c943dbc0448), [`7ef6e2c`](https://github.com/mastra-ai/mastra/commit/7ef6e2c61be5a42e26f55d15b5902866fc76634f), [`b12d2a5`](https://github.com/mastra-ai/mastra/commit/b12d2a59a48be0477cabae66eb6cf0fc94a7d40d), [`fa37d39`](https://github.com/mastra-ai/mastra/commit/fa37d39910421feaf8847716292e3d65dd4f30c2), [`b12d2a5`](https://github.com/mastra-ai/mastra/commit/b12d2a59a48be0477cabae66eb6cf0fc94a7d40d), [`71c38bf`](https://github.com/mastra-ai/mastra/commit/71c38bf905905148ecd0e75c07c1f9825d299b76), [`f993c38`](https://github.com/mastra-ai/mastra/commit/f993c3848c97479b813231be872443bedeced6ab), [`f51849a`](https://github.com/mastra-ai/mastra/commit/f51849a568935122b5100b7ee69704e6d680cf7b), [`9bf3a0d`](https://github.com/mastra-ai/mastra/commit/9bf3a0dac602787925f1762f1f0387d7b4a59620), [`cafa045`](https://github.com/mastra-ai/mastra/commit/cafa0453c9de141ad50c09a13894622dffdd9978), [`1fd9ddb`](https://github.com/mastra-ai/mastra/commit/1fd9ddbb3fe83b281b12bd2e27e426ae86288266), [`6135ef4`](https://github.com/mastra-ai/mastra/commit/6135ef4f5288652bf45f616ec590607e4c95f443), [`d9d228c`](https://github.com/mastra-ai/mastra/commit/d9d228c0c6ae82ae6ce3b540a3a56b2b1c2b8d98), [`5576507`](https://github.com/mastra-ai/mastra/commit/55765071e360fb97e443aa0a91ccf7e1cd8d92aa), [`79d69c9`](https://github.com/mastra-ai/mastra/commit/79d69c9d5f842ff1c31352fb6026f04c1f6190f3), [`94f44b8`](https://github.com/mastra-ai/mastra/commit/94f44b827ce57b179e50f4916a84c0fa6e7f3b8c), [`13187db`](https://github.com/mastra-ai/mastra/commit/13187dbac880174232dedc5a501ff6c5d0fe59bc), [`2ae5311`](https://github.com/mastra-ai/mastra/commit/2ae531185fff66a80fa165c0999e3d801900e89d), [`6135ef4`](https://github.com/mastra-ai/mastra/commit/6135ef4f5288652bf45f616ec590607e4c95f443)]:
|
|
8
|
+
- @mastra/core@0.0.0-agent-chat-ui-20260305212602
|
|
9
|
+
|
|
10
|
+
## 1.0.2
|
|
11
|
+
|
|
12
|
+
### Patch Changes
|
|
13
|
+
|
|
14
|
+
- Expanded `@mastra/auth-better-auth` to implement the new auth interfaces (`IUserProvider`, `ISessionProvider`, `ICredentialsProvider`) from `@mastra/core/auth`. Adds support for username/password credential flows alongside the existing token-based authentication. ([#13163](https://github.com/mastra-ai/mastra/pull/13163))
|
|
15
|
+
|
|
16
|
+
- Updated dependencies [[`504fc8b`](https://github.com/mastra-ai/mastra/commit/504fc8b9d0ddab717577ad3bf9c95ea4bd5377bd), [`f9c150b`](https://github.com/mastra-ai/mastra/commit/f9c150b7595ad05ad9cc9a11098e2944361e8c22), [`88de7e8`](https://github.com/mastra-ai/mastra/commit/88de7e8dfe4b7e1951a9e441bb33136e705ce24e), [`edee4b3`](https://github.com/mastra-ai/mastra/commit/edee4b37dff0af515fc7cc0e8d71ee39e6a762f0), [`3790c75`](https://github.com/mastra-ai/mastra/commit/3790c7578cc6a47d854eb12d89e6b1912867fe29), [`e7a235b`](https://github.com/mastra-ai/mastra/commit/e7a235be6472e0c870ed6c791ddb17c492dc188b), [`d51d298`](https://github.com/mastra-ai/mastra/commit/d51d298953967aab1f58ec965b644d109214f085), [`6dbeeb9`](https://github.com/mastra-ai/mastra/commit/6dbeeb94a8b1eebb727300d1a98961f882180794), [`d5f0d8d`](https://github.com/mastra-ai/mastra/commit/d5f0d8d6a03e515ddaa9b5da19b7e44b8357b07b), [`09c3b18`](https://github.com/mastra-ai/mastra/commit/09c3b1802ff14e243a8a8baea327440bc8cc2e32), [`b896379`](https://github.com/mastra-ai/mastra/commit/b8963791c6afa79484645fcec596a201f936b9a2), [`85c84eb`](https://github.com/mastra-ai/mastra/commit/85c84ebb78aebfcba9d209c8e152b16d7a00cb71), [`a89272a`](https://github.com/mastra-ai/mastra/commit/a89272a5d71939b9fcd284e6a6dc1dd091a6bdcf), [`ee9c8df`](https://github.com/mastra-ai/mastra/commit/ee9c8df644f19d055af5f496bf4942705f5a47b7), [`77b4a25`](https://github.com/mastra-ai/mastra/commit/77b4a254e51907f8ff3a3ba95596a18e93ae4b35), [`276246e`](https://github.com/mastra-ai/mastra/commit/276246e0b9066a1ea48bbc70df84dbe528daaf99), [`08ecfdb`](https://github.com/mastra-ai/mastra/commit/08ecfdbdad6fb8285deef86a034bdf4a6047cfca), [`d5f628c`](https://github.com/mastra-ai/mastra/commit/d5f628ca86c6f6f3ff1035d52f635df32dd81cab), [`524c0f3`](https://github.com/mastra-ai/mastra/commit/524c0f3c434c3d9d18f66338dcef383d6161b59c), [`c18a0e9`](https://github.com/mastra-ai/mastra/commit/c18a0e9cef1e4ca004b2963d35e4cfc031971eac), [`4bd21ea`](https://github.com/mastra-ai/mastra/commit/4bd21ea43d44d0a0427414fc047577f9f0aa3bec), [`115a7a4`](https://github.com/mastra-ai/mastra/commit/115a7a47db5e9896fec12ae6507501adb9ec89bf), [`22a48ae`](https://github.com/mastra-ai/mastra/commit/22a48ae2513eb54d8d79dad361fddbca97a155e8), [`3c6ef79`](https://github.com/mastra-ai/mastra/commit/3c6ef798481e00d6d22563be2de98818fd4dd5e0), [`9311c17`](https://github.com/mastra-ai/mastra/commit/9311c17d7a0640d9c4da2e71b814dc67c57c6369), [`7edf78f`](https://github.com/mastra-ai/mastra/commit/7edf78f80422c43e84585f08ba11df0d4d0b73c5), [`1c4221c`](https://github.com/mastra-ai/mastra/commit/1c4221cf6032ec98d0e094d4ee11da3e48490d96), [`d25b9ea`](https://github.com/mastra-ai/mastra/commit/d25b9eabd400167255a97b690ffbc4ee4097ded5), [`fe1ce5c`](https://github.com/mastra-ai/mastra/commit/fe1ce5c9211c03d561606fda95cbfe7df1d9a9b5), [`b03c0e0`](https://github.com/mastra-ai/mastra/commit/b03c0e0389a799523929a458b0509c9e4244d562), [`0a8366b`](https://github.com/mastra-ai/mastra/commit/0a8366b0a692fcdde56c4d526e4cf03c502ae4ac), [`85664e9`](https://github.com/mastra-ai/mastra/commit/85664e9fd857320fbc245e301f764f45f66f32a3), [`bc79650`](https://github.com/mastra-ai/mastra/commit/bc796500c6e0334faa158a96077e3fb332274869), [`9257d01`](https://github.com/mastra-ai/mastra/commit/9257d01d1366d81f84c582fe02b5e200cf9621f4), [`3a3a59e`](https://github.com/mastra-ai/mastra/commit/3a3a59e8ffaa6a985fe3d9a126a3f5ade11a6724), [`3108d4e`](https://github.com/mastra-ai/mastra/commit/3108d4e649c9fddbf03253a6feeb388a5fa9fa5a), [`0c33b2c`](https://github.com/mastra-ai/mastra/commit/0c33b2c9db537f815e1c59e2c898ffce2e395a79), [`191e5bd`](https://github.com/mastra-ai/mastra/commit/191e5bd29b82f5bda35243945790da7bc7b695c2), [`f77cd94`](https://github.com/mastra-ai/mastra/commit/f77cd94c44eabed490384e7d19232a865e13214c), [`e8135c7`](https://github.com/mastra-ai/mastra/commit/e8135c7e300dac5040670eec7eab896ac6092e30), [`daca48f`](https://github.com/mastra-ai/mastra/commit/daca48f0fb17b7ae0b62a2ac40cf0e491b2fd0b7), [`257d14f`](https://github.com/mastra-ai/mastra/commit/257d14faca5931f2e4186fc165b6f0b1f915deee), [`352f25d`](https://github.com/mastra-ai/mastra/commit/352f25da316b24cdd5b410fd8dddf6a8b763da2a), [`93477d0`](https://github.com/mastra-ai/mastra/commit/93477d0769b8a13ea5ed73d508d967fb23eaeed9), [`31c78b3`](https://github.com/mastra-ai/mastra/commit/31c78b3eb28f58a8017f1dcc795c33214d87feac), [`0bc0720`](https://github.com/mastra-ai/mastra/commit/0bc07201095791858087cc56f353fcd65e87ab54), [`36516ac`](https://github.com/mastra-ai/mastra/commit/36516aca1021cbeb42e74751b46a2614101f37c8), [`e947652`](https://github.com/mastra-ai/mastra/commit/e9476527fdecb4449e54570e80dfaf8466901254), [`3c6ef79`](https://github.com/mastra-ai/mastra/commit/3c6ef798481e00d6d22563be2de98818fd4dd5e0), [`9257d01`](https://github.com/mastra-ai/mastra/commit/9257d01d1366d81f84c582fe02b5e200cf9621f4), [`ec248f6`](https://github.com/mastra-ai/mastra/commit/ec248f6b56e8a037c066c49b2178e2507471d988)]:
|
|
17
|
+
- @mastra/core@1.9.0
|
|
18
|
+
|
|
19
|
+
## 1.0.2-alpha.0
|
|
20
|
+
|
|
21
|
+
### Patch Changes
|
|
22
|
+
|
|
23
|
+
- Expanded `@mastra/auth-better-auth` to implement the new auth interfaces (`IUserProvider`, `ISessionProvider`, `ICredentialsProvider`) from `@mastra/core/auth`. Adds support for username/password credential flows alongside the existing token-based authentication. ([#13163](https://github.com/mastra-ai/mastra/pull/13163))
|
|
24
|
+
|
|
25
|
+
- Updated dependencies [[`504fc8b`](https://github.com/mastra-ai/mastra/commit/504fc8b9d0ddab717577ad3bf9c95ea4bd5377bd), [`f9c150b`](https://github.com/mastra-ai/mastra/commit/f9c150b7595ad05ad9cc9a11098e2944361e8c22), [`88de7e8`](https://github.com/mastra-ai/mastra/commit/88de7e8dfe4b7e1951a9e441bb33136e705ce24e), [`edee4b3`](https://github.com/mastra-ai/mastra/commit/edee4b37dff0af515fc7cc0e8d71ee39e6a762f0), [`3790c75`](https://github.com/mastra-ai/mastra/commit/3790c7578cc6a47d854eb12d89e6b1912867fe29), [`e7a235b`](https://github.com/mastra-ai/mastra/commit/e7a235be6472e0c870ed6c791ddb17c492dc188b), [`d51d298`](https://github.com/mastra-ai/mastra/commit/d51d298953967aab1f58ec965b644d109214f085), [`6dbeeb9`](https://github.com/mastra-ai/mastra/commit/6dbeeb94a8b1eebb727300d1a98961f882180794), [`d5f0d8d`](https://github.com/mastra-ai/mastra/commit/d5f0d8d6a03e515ddaa9b5da19b7e44b8357b07b), [`09c3b18`](https://github.com/mastra-ai/mastra/commit/09c3b1802ff14e243a8a8baea327440bc8cc2e32), [`b896379`](https://github.com/mastra-ai/mastra/commit/b8963791c6afa79484645fcec596a201f936b9a2), [`85c84eb`](https://github.com/mastra-ai/mastra/commit/85c84ebb78aebfcba9d209c8e152b16d7a00cb71), [`a89272a`](https://github.com/mastra-ai/mastra/commit/a89272a5d71939b9fcd284e6a6dc1dd091a6bdcf), [`ee9c8df`](https://github.com/mastra-ai/mastra/commit/ee9c8df644f19d055af5f496bf4942705f5a47b7), [`77b4a25`](https://github.com/mastra-ai/mastra/commit/77b4a254e51907f8ff3a3ba95596a18e93ae4b35), [`276246e`](https://github.com/mastra-ai/mastra/commit/276246e0b9066a1ea48bbc70df84dbe528daaf99), [`08ecfdb`](https://github.com/mastra-ai/mastra/commit/08ecfdbdad6fb8285deef86a034bdf4a6047cfca), [`d5f628c`](https://github.com/mastra-ai/mastra/commit/d5f628ca86c6f6f3ff1035d52f635df32dd81cab), [`524c0f3`](https://github.com/mastra-ai/mastra/commit/524c0f3c434c3d9d18f66338dcef383d6161b59c), [`c18a0e9`](https://github.com/mastra-ai/mastra/commit/c18a0e9cef1e4ca004b2963d35e4cfc031971eac), [`4bd21ea`](https://github.com/mastra-ai/mastra/commit/4bd21ea43d44d0a0427414fc047577f9f0aa3bec), [`115a7a4`](https://github.com/mastra-ai/mastra/commit/115a7a47db5e9896fec12ae6507501adb9ec89bf), [`22a48ae`](https://github.com/mastra-ai/mastra/commit/22a48ae2513eb54d8d79dad361fddbca97a155e8), [`3c6ef79`](https://github.com/mastra-ai/mastra/commit/3c6ef798481e00d6d22563be2de98818fd4dd5e0), [`9311c17`](https://github.com/mastra-ai/mastra/commit/9311c17d7a0640d9c4da2e71b814dc67c57c6369), [`7edf78f`](https://github.com/mastra-ai/mastra/commit/7edf78f80422c43e84585f08ba11df0d4d0b73c5), [`1c4221c`](https://github.com/mastra-ai/mastra/commit/1c4221cf6032ec98d0e094d4ee11da3e48490d96), [`d25b9ea`](https://github.com/mastra-ai/mastra/commit/d25b9eabd400167255a97b690ffbc4ee4097ded5), [`fe1ce5c`](https://github.com/mastra-ai/mastra/commit/fe1ce5c9211c03d561606fda95cbfe7df1d9a9b5), [`b03c0e0`](https://github.com/mastra-ai/mastra/commit/b03c0e0389a799523929a458b0509c9e4244d562), [`0a8366b`](https://github.com/mastra-ai/mastra/commit/0a8366b0a692fcdde56c4d526e4cf03c502ae4ac), [`85664e9`](https://github.com/mastra-ai/mastra/commit/85664e9fd857320fbc245e301f764f45f66f32a3), [`bc79650`](https://github.com/mastra-ai/mastra/commit/bc796500c6e0334faa158a96077e3fb332274869), [`9257d01`](https://github.com/mastra-ai/mastra/commit/9257d01d1366d81f84c582fe02b5e200cf9621f4), [`3a3a59e`](https://github.com/mastra-ai/mastra/commit/3a3a59e8ffaa6a985fe3d9a126a3f5ade11a6724), [`3108d4e`](https://github.com/mastra-ai/mastra/commit/3108d4e649c9fddbf03253a6feeb388a5fa9fa5a), [`0c33b2c`](https://github.com/mastra-ai/mastra/commit/0c33b2c9db537f815e1c59e2c898ffce2e395a79), [`191e5bd`](https://github.com/mastra-ai/mastra/commit/191e5bd29b82f5bda35243945790da7bc7b695c2), [`f77cd94`](https://github.com/mastra-ai/mastra/commit/f77cd94c44eabed490384e7d19232a865e13214c), [`e8135c7`](https://github.com/mastra-ai/mastra/commit/e8135c7e300dac5040670eec7eab896ac6092e30), [`daca48f`](https://github.com/mastra-ai/mastra/commit/daca48f0fb17b7ae0b62a2ac40cf0e491b2fd0b7), [`257d14f`](https://github.com/mastra-ai/mastra/commit/257d14faca5931f2e4186fc165b6f0b1f915deee), [`352f25d`](https://github.com/mastra-ai/mastra/commit/352f25da316b24cdd5b410fd8dddf6a8b763da2a), [`93477d0`](https://github.com/mastra-ai/mastra/commit/93477d0769b8a13ea5ed73d508d967fb23eaeed9), [`31c78b3`](https://github.com/mastra-ai/mastra/commit/31c78b3eb28f58a8017f1dcc795c33214d87feac), [`0bc0720`](https://github.com/mastra-ai/mastra/commit/0bc07201095791858087cc56f353fcd65e87ab54), [`36516ac`](https://github.com/mastra-ai/mastra/commit/36516aca1021cbeb42e74751b46a2614101f37c8), [`e947652`](https://github.com/mastra-ai/mastra/commit/e9476527fdecb4449e54570e80dfaf8466901254), [`3c6ef79`](https://github.com/mastra-ai/mastra/commit/3c6ef798481e00d6d22563be2de98818fd4dd5e0), [`9257d01`](https://github.com/mastra-ai/mastra/commit/9257d01d1366d81f84c582fe02b5e200cf9621f4), [`ec248f6`](https://github.com/mastra-ai/mastra/commit/ec248f6b56e8a037c066c49b2178e2507471d988)]:
|
|
26
|
+
- @mastra/core@1.9.0-alpha.0
|
|
27
|
+
|
|
28
|
+
## 1.0.1
|
|
29
|
+
|
|
30
|
+
### Patch Changes
|
|
31
|
+
|
|
32
|
+
- dependencies updates: ([#12964](https://github.com/mastra-ai/mastra/pull/12964))
|
|
33
|
+
- Updated dependency [`better-auth@^1.4.18` ↗︎](https://www.npmjs.com/package/better-auth/v/1.4.18) (from `^1.4.5`, in `dependencies`)
|
|
34
|
+
|
|
35
|
+
## 1.0.1-alpha.0
|
|
36
|
+
|
|
37
|
+
### Patch Changes
|
|
38
|
+
|
|
39
|
+
- dependencies updates: ([#12964](https://github.com/mastra-ai/mastra/pull/12964))
|
|
40
|
+
- Updated dependency [`better-auth@^1.4.18` ↗︎](https://www.npmjs.com/package/better-auth/v/1.4.18) (from `^1.4.5`, in `dependencies`)
|
|
41
|
+
|
|
42
|
+
## 1.0.0
|
|
43
|
+
|
|
44
|
+
### Minor Changes
|
|
45
|
+
|
|
46
|
+
- Add Better Auth authentication provider ([#10658](https://github.com/mastra-ai/mastra/pull/10658))
|
|
47
|
+
|
|
48
|
+
Adds a new authentication provider for Better Auth, a self-hosted, open-source authentication framework.
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
import { betterAuth } from 'better-auth';
|
|
52
|
+
import { MastraAuthBetterAuth } from '@mastra/auth-better-auth';
|
|
53
|
+
import { Mastra } from '@mastra/core';
|
|
54
|
+
|
|
55
|
+
// Create your Better Auth instance
|
|
56
|
+
const auth = betterAuth({
|
|
57
|
+
database: {
|
|
58
|
+
provider: 'postgresql',
|
|
59
|
+
url: process.env.DATABASE_URL!,
|
|
60
|
+
},
|
|
61
|
+
emailAndPassword: {
|
|
62
|
+
enabled: true,
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
// Create the Mastra auth provider
|
|
67
|
+
const mastraAuth = new MastraAuthBetterAuth({
|
|
68
|
+
auth,
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
// Use with Mastra
|
|
72
|
+
const mastra = new Mastra({
|
|
73
|
+
server: {
|
|
74
|
+
auth: mastraAuth,
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## 1.0.0-beta.2
|
|
80
|
+
|
|
81
|
+
### Minor Changes
|
|
82
|
+
|
|
83
|
+
- Add Better Auth authentication provider ([#10658](https://github.com/mastra-ai/mastra/pull/10658))
|
|
84
|
+
|
|
85
|
+
Adds a new authentication provider for Better Auth, a self-hosted, open-source authentication framework.
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
import { betterAuth } from 'better-auth';
|
|
89
|
+
import { MastraAuthBetterAuth } from '@mastra/auth-better-auth';
|
|
90
|
+
import { Mastra } from '@mastra/core';
|
|
91
|
+
|
|
92
|
+
// Create your Better Auth instance
|
|
93
|
+
const auth = betterAuth({
|
|
94
|
+
database: {
|
|
95
|
+
provider: 'postgresql',
|
|
96
|
+
url: process.env.DATABASE_URL!,
|
|
97
|
+
},
|
|
98
|
+
emailAndPassword: {
|
|
99
|
+
enabled: true,
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
// Create the Mastra auth provider
|
|
104
|
+
const mastraAuth = new MastraAuthBetterAuth({
|
|
105
|
+
auth,
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
// Use with Mastra
|
|
109
|
+
const mastra = new Mastra({
|
|
110
|
+
server: {
|
|
111
|
+
auth: mastraAuth,
|
|
112
|
+
},
|
|
113
|
+
});
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## 1.0.0-beta.1
|
|
117
|
+
|
|
118
|
+
### Major Changes
|
|
119
|
+
|
|
120
|
+
- Initial release of Better Auth integration for Mastra
|
|
121
|
+
- Self-hosted authentication provider using Better Auth
|
|
122
|
+
- Support for session-based authentication
|
|
123
|
+
- Custom authorization logic support
|
|
124
|
+
- Route configuration for public/protected paths
|
package/LICENSE.md
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
Portions of this software are licensed as follows:
|
|
2
|
+
|
|
3
|
+
- All content that resides under any directory named "ee/" within this
|
|
4
|
+
repository, including but not limited to:
|
|
5
|
+
- `packages/core/src/auth/ee/`
|
|
6
|
+
- `packages/server/src/server/auth/ee/`
|
|
7
|
+
is licensed under the license defined in `ee/LICENSE`.
|
|
8
|
+
|
|
9
|
+
- All third-party components incorporated into the Mastra Software are
|
|
10
|
+
licensed under the original license provided by the owner of the
|
|
11
|
+
applicable component.
|
|
12
|
+
|
|
13
|
+
- Content outside of the above-mentioned directories or restrictions is
|
|
14
|
+
available under the "Apache License 2.0" as defined below.
|
|
15
|
+
|
|
16
|
+
# Apache License 2.0
|
|
17
|
+
|
|
18
|
+
Copyright (c) 2025 Kepler Software, Inc.
|
|
19
|
+
|
|
20
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
21
|
+
you may not use this file except in compliance with the License.
|
|
22
|
+
You may obtain a copy of the License at
|
|
23
|
+
|
|
24
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
25
|
+
|
|
26
|
+
Unless required by applicable law or agreed to in writing, software
|
|
27
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
28
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
29
|
+
See the License for the specific language governing permissions and
|
|
30
|
+
limitations under the License.
|
package/README.md
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# @mastra/auth-better-auth
|
|
2
|
+
|
|
3
|
+
Better Auth integration for Mastra - a self-hosted, open-source authentication solution.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @mastra/auth-better-auth better-auth
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { betterAuth } from 'better-auth';
|
|
15
|
+
import { MastraAuthBetterAuth } from '@mastra/auth-better-auth';
|
|
16
|
+
import { Mastra } from '@mastra/core';
|
|
17
|
+
|
|
18
|
+
// Create your Better Auth instance
|
|
19
|
+
const auth = betterAuth({
|
|
20
|
+
database: {
|
|
21
|
+
provider: 'postgresql',
|
|
22
|
+
url: process.env.DATABASE_URL!,
|
|
23
|
+
},
|
|
24
|
+
emailAndPassword: {
|
|
25
|
+
enabled: true,
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
// Create the Mastra auth provider
|
|
30
|
+
const mastraAuth = new MastraAuthBetterAuth({
|
|
31
|
+
auth,
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
// Use with Mastra
|
|
35
|
+
const mastra = new Mastra({
|
|
36
|
+
server: {
|
|
37
|
+
auth: mastraAuth,
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Configuration Options
|
|
43
|
+
|
|
44
|
+
| Option | Type | Required | Description |
|
|
45
|
+
| --------------- | ------------------------------------- | -------- | ------------------------------------------------------------ |
|
|
46
|
+
| `auth` | `Auth` | Yes | Your Better Auth instance created via `betterAuth({ ... })` |
|
|
47
|
+
| `name` | `string` | No | Custom name for the auth provider (default: `'better-auth'`) |
|
|
48
|
+
| `authorizeUser` | `(user, request) => Promise<boolean>` | No | Custom authorization logic |
|
|
49
|
+
| `public` | `string[]` | No | Public routes that don't require authentication |
|
|
50
|
+
| `protected` | `string[]` | No | Protected routes that require authentication |
|
|
51
|
+
|
|
52
|
+
## Custom Authorization
|
|
53
|
+
|
|
54
|
+
You can provide custom authorization logic:
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
const mastraAuth = new MastraAuthBetterAuth({
|
|
58
|
+
auth,
|
|
59
|
+
async authorizeUser(user) {
|
|
60
|
+
// Only allow verified emails
|
|
61
|
+
return user?.user?.emailVerified === true;
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Role-Based Access Control
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
const mastraAuth = new MastraAuthBetterAuth({
|
|
70
|
+
auth,
|
|
71
|
+
async authorizeUser(user) {
|
|
72
|
+
// Check for admin role (assuming you have a role field)
|
|
73
|
+
const userWithRole = user?.user as any;
|
|
74
|
+
return userWithRole?.role === 'admin';
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Route Configuration
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
const mastraAuth = new MastraAuthBetterAuth({
|
|
83
|
+
auth,
|
|
84
|
+
public: ['/health', '/api/status'],
|
|
85
|
+
protected: ['/api/*', '/admin/*'],
|
|
86
|
+
});
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Why Better Auth?
|
|
90
|
+
|
|
91
|
+
Better Auth is a self-hosted, open-source authentication framework that gives you:
|
|
92
|
+
|
|
93
|
+
- **Full control** over your authentication system
|
|
94
|
+
- **No vendor lock-in** - host it yourself
|
|
95
|
+
- **Flexible** - works with various databases and providers
|
|
96
|
+
- **TypeScript-first** - full type safety
|
|
97
|
+
- **Plugin system** - extend with OAuth, 2FA, organizations, etc.
|
|
98
|
+
|
|
99
|
+
## Resources
|
|
100
|
+
|
|
101
|
+
- [Better Auth Documentation](https://better-auth.com)
|
|
102
|
+
- [Mastra Documentation](https://mastra.ai/docs)
|
|
103
|
+
- [GitHub Repository](https://github.com/mastra-ai/mastra)
|
|
104
|
+
|
|
105
|
+
## License
|
|
106
|
+
|
|
107
|
+
Apache-2.0
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var server = require('@mastra/core/server');
|
|
4
|
+
|
|
5
|
+
// src/index.ts
|
|
6
|
+
function mapBetterAuthUserToEEUser(user) {
|
|
7
|
+
return {
|
|
8
|
+
id: user.id,
|
|
9
|
+
email: user.email,
|
|
10
|
+
name: user.name,
|
|
11
|
+
avatarUrl: user.image ?? void 0,
|
|
12
|
+
metadata: {
|
|
13
|
+
emailVerified: user.emailVerified,
|
|
14
|
+
createdAt: user.createdAt,
|
|
15
|
+
updatedAt: user.updatedAt
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
var MastraAuthBetterAuth = class extends server.MastraAuthProvider {
|
|
20
|
+
auth;
|
|
21
|
+
signUpEnabledConfig;
|
|
22
|
+
sessionCookieName;
|
|
23
|
+
constructor(options) {
|
|
24
|
+
super({ name: options?.name ?? "better-auth" });
|
|
25
|
+
if (!options.auth) {
|
|
26
|
+
throw new Error(
|
|
27
|
+
"Better Auth instance is required. Please provide the auth option with your Better Auth instance created via betterAuth({ ... })"
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
this.auth = options.auth;
|
|
31
|
+
this.signUpEnabledConfig = options.signUpEnabled ?? true;
|
|
32
|
+
const authWithOptions = this.auth;
|
|
33
|
+
const prefix = authWithOptions.options?.advanced?.cookiePrefix ?? "better-auth";
|
|
34
|
+
this.sessionCookieName = `${prefix}.session_token`;
|
|
35
|
+
this.registerOptions(options);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Check if sign-up is enabled.
|
|
39
|
+
* Implements ICredentialsProvider.isSignUpEnabled.
|
|
40
|
+
*/
|
|
41
|
+
isSignUpEnabled() {
|
|
42
|
+
return this.signUpEnabledConfig;
|
|
43
|
+
}
|
|
44
|
+
// ============================================
|
|
45
|
+
// IUserProvider implementation (EE capability)
|
|
46
|
+
// License check happens in buildCapabilities()
|
|
47
|
+
// ============================================
|
|
48
|
+
/**
|
|
49
|
+
* Get current user from request.
|
|
50
|
+
* Implements IUserProvider for EE user awareness in Studio.
|
|
51
|
+
*
|
|
52
|
+
* @param request - Incoming HTTP request
|
|
53
|
+
* @returns EE User object or null if not authenticated
|
|
54
|
+
*/
|
|
55
|
+
async getCurrentUser(request) {
|
|
56
|
+
try {
|
|
57
|
+
const result = await this.auth.api.getSession({
|
|
58
|
+
headers: request.headers
|
|
59
|
+
});
|
|
60
|
+
if (!result?.user) return null;
|
|
61
|
+
return mapBetterAuthUserToEEUser(result.user);
|
|
62
|
+
} catch {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Get user by ID.
|
|
68
|
+
* Implements IUserProvider for EE user awareness.
|
|
69
|
+
*
|
|
70
|
+
* Note: Better Auth doesn't expose a direct getUser API.
|
|
71
|
+
* For full functionality, you may need to implement this using
|
|
72
|
+
* direct database access in a subclass.
|
|
73
|
+
*
|
|
74
|
+
* @param userId - User identifier
|
|
75
|
+
* @returns EE User object or null if not found
|
|
76
|
+
*/
|
|
77
|
+
async getUser(_userId) {
|
|
78
|
+
console.warn(
|
|
79
|
+
"[MastraAuthBetterAuth] getUser() requires direct database access. Override this method in a subclass for full user lookup support."
|
|
80
|
+
);
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Get URL to user's profile page.
|
|
85
|
+
* Optional IUserProvider method.
|
|
86
|
+
*/
|
|
87
|
+
getUserProfileUrl(user) {
|
|
88
|
+
return `/profile/${user.id}`;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Authenticate a bearer token by verifying the session with Better Auth.
|
|
92
|
+
*
|
|
93
|
+
* This method extracts the session from the request headers using
|
|
94
|
+
* Better Auth's `api.getSession()` endpoint.
|
|
95
|
+
*
|
|
96
|
+
* @param token - The bearer token (session token) to authenticate
|
|
97
|
+
* @param request - The Hono request object containing headers
|
|
98
|
+
* @returns The authenticated user and session, or null if authentication fails
|
|
99
|
+
*/
|
|
100
|
+
async authenticateToken(token, request) {
|
|
101
|
+
try {
|
|
102
|
+
const headers = new Headers();
|
|
103
|
+
const rawRequest = "raw" in request ? request.raw : request;
|
|
104
|
+
const cookieHeader = rawRequest.headers.get("Cookie");
|
|
105
|
+
if (cookieHeader) {
|
|
106
|
+
headers.set("Cookie", cookieHeader);
|
|
107
|
+
}
|
|
108
|
+
const hasSessionCookie = !!cookieHeader?.split(";").some((pair) => {
|
|
109
|
+
const [key] = pair.trim().split("=");
|
|
110
|
+
return key?.trim() === this.sessionCookieName;
|
|
111
|
+
});
|
|
112
|
+
if (token && !hasSessionCookie) {
|
|
113
|
+
const existingCookies = cookieHeader ? `${cookieHeader}; ` : "";
|
|
114
|
+
headers.set("Cookie", `${existingCookies}${this.sessionCookieName}=${token}`);
|
|
115
|
+
}
|
|
116
|
+
const result = await this.auth.api.getSession({
|
|
117
|
+
headers
|
|
118
|
+
});
|
|
119
|
+
if (!result || !result.session || !result.user) {
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
return {
|
|
123
|
+
session: result.session,
|
|
124
|
+
user: result.user
|
|
125
|
+
};
|
|
126
|
+
} catch {
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Authorize a user for access.
|
|
132
|
+
*
|
|
133
|
+
* By default, any authenticated user with a valid session is authorized.
|
|
134
|
+
* You can override this behavior by providing a custom `authorizeUser` function
|
|
135
|
+
* in the constructor options.
|
|
136
|
+
*
|
|
137
|
+
* @param user - The authenticated user and session
|
|
138
|
+
* @returns True if the user is authorized, false otherwise
|
|
139
|
+
*/
|
|
140
|
+
async authorizeUser(user) {
|
|
141
|
+
return !!user?.session?.id && !!user?.user?.id;
|
|
142
|
+
}
|
|
143
|
+
// ============================================
|
|
144
|
+
// ICredentialsProvider implementation (EE capability)
|
|
145
|
+
// License check happens in buildCapabilities()
|
|
146
|
+
// ============================================
|
|
147
|
+
/**
|
|
148
|
+
* Sign in with email and password.
|
|
149
|
+
* Implements ICredentialsProvider for EE credentials auth.
|
|
150
|
+
*
|
|
151
|
+
* @param email - User email
|
|
152
|
+
* @param password - User password
|
|
153
|
+
* @param request - Incoming HTTP request
|
|
154
|
+
* @returns Result with user and session cookies
|
|
155
|
+
* @throws Error if credentials are invalid
|
|
156
|
+
*/
|
|
157
|
+
async signIn(email, password, request) {
|
|
158
|
+
const headers = request?.headers ?? new Headers();
|
|
159
|
+
const response = await this.auth.api.signInEmail({
|
|
160
|
+
body: { email, password },
|
|
161
|
+
headers,
|
|
162
|
+
asResponse: true
|
|
163
|
+
});
|
|
164
|
+
if (!response.ok) {
|
|
165
|
+
const errorData = await response.json().catch(() => ({}));
|
|
166
|
+
throw new Error(errorData.message || "Invalid email or password");
|
|
167
|
+
}
|
|
168
|
+
const result = await response.json();
|
|
169
|
+
if (!result?.user) {
|
|
170
|
+
throw new Error("Invalid email or password");
|
|
171
|
+
}
|
|
172
|
+
const cookies = [];
|
|
173
|
+
const setCookieHeader = response.headers.get("set-cookie");
|
|
174
|
+
if (setCookieHeader) {
|
|
175
|
+
cookies.push(...setCookieHeader.split(/,(?=\s*\w+=)/));
|
|
176
|
+
}
|
|
177
|
+
return {
|
|
178
|
+
user: mapBetterAuthUserToEEUser(result.user),
|
|
179
|
+
token: result.token ?? void 0,
|
|
180
|
+
cookies
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Sign up with email and password.
|
|
185
|
+
* Implements ICredentialsProvider for EE credentials auth.
|
|
186
|
+
*
|
|
187
|
+
* @param email - User email
|
|
188
|
+
* @param password - User password
|
|
189
|
+
* @param name - Optional display name
|
|
190
|
+
* @param request - Incoming HTTP request
|
|
191
|
+
* @returns Result with new user and session cookies
|
|
192
|
+
* @throws Error if sign up fails
|
|
193
|
+
*/
|
|
194
|
+
async signUp(email, password, name, request) {
|
|
195
|
+
const displayName = name ?? email.split("@")[0] ?? "User";
|
|
196
|
+
const headers = request?.headers ?? new Headers();
|
|
197
|
+
const response = await this.auth.api.signUpEmail({
|
|
198
|
+
body: { email, password, name: displayName },
|
|
199
|
+
headers,
|
|
200
|
+
asResponse: true
|
|
201
|
+
});
|
|
202
|
+
if (!response.ok) {
|
|
203
|
+
const errorData = await response.json().catch(() => ({}));
|
|
204
|
+
throw new Error(errorData.message || "Failed to create account");
|
|
205
|
+
}
|
|
206
|
+
const result = await response.json();
|
|
207
|
+
if (!result?.user) {
|
|
208
|
+
throw new Error("Failed to create account");
|
|
209
|
+
}
|
|
210
|
+
const cookies = [];
|
|
211
|
+
const setCookieHeader = response.headers.get("set-cookie");
|
|
212
|
+
if (setCookieHeader) {
|
|
213
|
+
cookies.push(...setCookieHeader.split(/,(?=\s*\w+=)/));
|
|
214
|
+
}
|
|
215
|
+
return {
|
|
216
|
+
user: mapBetterAuthUserToEEUser(result.user),
|
|
217
|
+
token: result.token ?? void 0,
|
|
218
|
+
cookies
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Get the underlying Better Auth instance.
|
|
223
|
+
* Useful for accessing Better Auth APIs directly.
|
|
224
|
+
*/
|
|
225
|
+
getAuth() {
|
|
226
|
+
return this.auth;
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Get headers to clear the session cookies on logout.
|
|
230
|
+
* Partial ISessionProvider implementation for logout support.
|
|
231
|
+
*
|
|
232
|
+
* Clears Better Auth's default session cookies.
|
|
233
|
+
*/
|
|
234
|
+
getClearSessionHeaders() {
|
|
235
|
+
const cookies = [
|
|
236
|
+
`${this.sessionCookieName}=; Path=/; HttpOnly; SameSite=Lax; Max-Age=0`,
|
|
237
|
+
`${this.sessionCookieName}_sig=; Path=/; HttpOnly; SameSite=Lax; Max-Age=0`
|
|
238
|
+
];
|
|
239
|
+
return {
|
|
240
|
+
"Set-Cookie": cookies.join(", ")
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
exports.MastraAuthBetterAuth = MastraAuthBetterAuth;
|
|
246
|
+
//# sourceMappingURL=index.cjs.map
|
|
247
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"names":["MastraAuthProvider"],"mappings":"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","file":"index.cjs","sourcesContent":["import type { IUserProvider, ICredentialsProvider, CredentialsResult } from '@mastra/core/auth';\nimport type { EEUser } from '@mastra/core/auth/ee';\nimport type { MastraAuthProviderOptions } from '@mastra/core/server';\nimport { MastraAuthProvider } from '@mastra/core/server';\n\nimport type { Auth, Session, User } from 'better-auth';\nimport type { HonoRequest } from 'hono';\n\n/**\n * User type returned by Better Auth session verification.\n * Used internally for authentication token verification.\n */\nexport interface BetterAuthUser {\n session: Session;\n user: User;\n}\n\n/**\n * Maps Better Auth User to EE User format.\n */\nfunction mapBetterAuthUserToEEUser(user: User): EEUser {\n return {\n id: user.id,\n email: user.email,\n name: user.name,\n avatarUrl: user.image ?? undefined,\n metadata: {\n emailVerified: user.emailVerified,\n createdAt: user.createdAt,\n updatedAt: user.updatedAt,\n },\n };\n}\n\ninterface MastraAuthBetterAuthOptions extends MastraAuthProviderOptions<BetterAuthUser> {\n /**\n * The Better Auth instance to use for authentication.\n * This should be the result of calling `betterAuth({ ... })`.\n */\n auth: Auth;\n\n /**\n * Whether to allow new user registration via sign-up.\n * Set to false to disable public registration.\n * @default true\n */\n signUpEnabled?: boolean;\n}\n\n/**\n * Mastra authentication provider for Better Auth.\n *\n * Better Auth is a self-hosted, open-source authentication framework\n * that gives you full control over your authentication system.\n *\n * @example\n * ```typescript\n * import { betterAuth } from 'better-auth';\n * import { MastraAuthBetterAuth } from '@mastra/auth-better-auth';\n *\n * // Create your Better Auth instance\n * const auth = betterAuth({\n * database: {\n * provider: 'postgresql',\n * url: process.env.DATABASE_URL!,\n * },\n * emailAndPassword: {\n * enabled: true,\n * },\n * });\n *\n * // Create the Mastra auth provider\n * const mastraAuth = new MastraAuthBetterAuth({\n * auth,\n * });\n *\n * // Use with Mastra\n * const mastra = new Mastra({\n * server: {\n * auth: mastraAuth,\n * },\n * });\n * ```\n *\n * @see https://better-auth.com for Better Auth documentation\n */\nexport class MastraAuthBetterAuth\n extends MastraAuthProvider<BetterAuthUser>\n implements IUserProvider<EEUser>, ICredentialsProvider<EEUser>\n{\n protected auth: Auth;\n protected signUpEnabledConfig: boolean;\n public sessionCookieName: string;\n\n constructor(options: MastraAuthBetterAuthOptions) {\n super({ name: options?.name ?? 'better-auth' });\n\n if (!options.auth) {\n throw new Error(\n 'Better Auth instance is required. Please provide the auth option with your Better Auth instance created via betterAuth({ ... })',\n );\n }\n\n this.auth = options.auth;\n this.signUpEnabledConfig = options.signUpEnabled ?? true;\n\n // Derive the session cookie name from Better Auth's cookiePrefix option\n const authWithOptions = this.auth as unknown as { options?: { advanced?: { cookiePrefix?: string } } };\n const prefix = authWithOptions.options?.advanced?.cookiePrefix ?? 'better-auth';\n this.sessionCookieName = `${prefix}.session_token`;\n\n this.registerOptions(options);\n }\n\n /**\n * Check if sign-up is enabled.\n * Implements ICredentialsProvider.isSignUpEnabled.\n */\n isSignUpEnabled(): boolean {\n return this.signUpEnabledConfig;\n }\n\n // ============================================\n // IUserProvider implementation (EE capability)\n // License check happens in buildCapabilities()\n // ============================================\n\n /**\n * Get current user from request.\n * Implements IUserProvider for EE user awareness in Studio.\n *\n * @param request - Incoming HTTP request\n * @returns EE User object or null if not authenticated\n */\n async getCurrentUser(request: Request): Promise<EEUser | null> {\n try {\n const result = await this.auth.api.getSession({\n headers: request.headers,\n });\n\n if (!result?.user) return null;\n return mapBetterAuthUserToEEUser(result.user);\n } catch {\n return null;\n }\n }\n\n /**\n * Get user by ID.\n * Implements IUserProvider for EE user awareness.\n *\n * Note: Better Auth doesn't expose a direct getUser API.\n * For full functionality, you may need to implement this using\n * direct database access in a subclass.\n *\n * @param userId - User identifier\n * @returns EE User object or null if not found\n */\n async getUser(_userId: string): Promise<EEUser | null> {\n // Better Auth doesn't have a direct getUser API\n // Users can override this method with their own implementation\n // that queries the database directly\n console.warn(\n '[MastraAuthBetterAuth] getUser() requires direct database access. ' +\n 'Override this method in a subclass for full user lookup support.',\n );\n return null;\n }\n\n /**\n * Get URL to user's profile page.\n * Optional IUserProvider method.\n */\n getUserProfileUrl(user: EEUser): string {\n return `/profile/${user.id}`;\n }\n\n /**\n * Authenticate a bearer token by verifying the session with Better Auth.\n *\n * This method extracts the session from the request headers using\n * Better Auth's `api.getSession()` endpoint.\n *\n * @param token - The bearer token (session token) to authenticate\n * @param request - The Hono request object containing headers\n * @returns The authenticated user and session, or null if authentication fails\n */\n async authenticateToken(token: string, request: HonoRequest): Promise<BetterAuthUser | null> {\n try {\n // Better Auth's api.getSession() reads session tokens from the Cookie header\n const headers = new Headers();\n\n // The auth middleware may pass a raw Request (c.req.raw) instead of HonoRequest,\n // so unwrap via 'raw' property detection and use the standard Web API.\n const rawRequest: Request = 'raw' in request ? (request as any).raw : (request as unknown as Request);\n\n const cookieHeader = rawRequest.headers.get('Cookie');\n if (cookieHeader) {\n headers.set('Cookie', cookieHeader);\n }\n\n // Convert Bearer token to a session cookie if not already present.\n // better-auth ignores the Authorization header — it only reads from Cookie.\n const hasSessionCookie = !!cookieHeader?.split(';').some(pair => {\n const [key] = pair.trim().split('=');\n return key?.trim() === this.sessionCookieName;\n });\n if (token && !hasSessionCookie) {\n const existingCookies = cookieHeader ? `${cookieHeader}; ` : '';\n headers.set('Cookie', `${existingCookies}${this.sessionCookieName}=${token}`);\n }\n\n const result = await this.auth.api.getSession({\n headers,\n });\n\n if (!result || !result.session || !result.user) {\n return null;\n }\n\n return {\n session: result.session,\n user: result.user,\n };\n } catch {\n return null;\n }\n }\n\n /**\n * Authorize a user for access.\n *\n * By default, any authenticated user with a valid session is authorized.\n * You can override this behavior by providing a custom `authorizeUser` function\n * in the constructor options.\n *\n * @param user - The authenticated user and session\n * @returns True if the user is authorized, false otherwise\n */\n async authorizeUser(user: BetterAuthUser): Promise<boolean> {\n // By default, any authenticated user with a valid session is authorized\n return !!user?.session?.id && !!user?.user?.id;\n }\n\n // ============================================\n // ICredentialsProvider implementation (EE capability)\n // License check happens in buildCapabilities()\n // ============================================\n\n /**\n * Sign in with email and password.\n * Implements ICredentialsProvider for EE credentials auth.\n *\n * @param email - User email\n * @param password - User password\n * @param request - Incoming HTTP request\n * @returns Result with user and session cookies\n * @throws Error if credentials are invalid\n */\n async signIn(email: string, password: string, request: Request): Promise<CredentialsResult<EEUser>> {\n const headers = request?.headers ?? new Headers();\n\n // Use asResponse: true to get the full response with Set-Cookie headers\n const response = await this.auth.api.signInEmail({\n body: { email, password },\n headers,\n asResponse: true,\n });\n\n if (!response.ok) {\n const errorData = (await response.json().catch(() => ({}))) as { message?: string };\n throw new Error(errorData.message || 'Invalid email or password');\n }\n\n const result = (await response.json()) as { user?: User; token?: string | null };\n\n if (!result?.user) {\n throw new Error('Invalid email or password');\n }\n\n // Extract Set-Cookie headers from Better Auth response\n const cookies: string[] = [];\n const setCookieHeader = response.headers.get('set-cookie');\n if (setCookieHeader) {\n // Split multiple cookies (they may be comma-separated or in multiple headers)\n cookies.push(...setCookieHeader.split(/,(?=\\s*\\w+=)/));\n }\n\n return {\n user: mapBetterAuthUserToEEUser(result.user),\n token: result.token ?? undefined,\n cookies,\n };\n }\n\n /**\n * Sign up with email and password.\n * Implements ICredentialsProvider for EE credentials auth.\n *\n * @param email - User email\n * @param password - User password\n * @param name - Optional display name\n * @param request - Incoming HTTP request\n * @returns Result with new user and session cookies\n * @throws Error if sign up fails\n */\n async signUp(\n email: string,\n password: string,\n name: string | undefined,\n request: Request,\n ): Promise<CredentialsResult<EEUser>> {\n const displayName = name ?? email.split('@')[0] ?? 'User';\n const headers = request?.headers ?? new Headers();\n\n // Use asResponse: true to get the full response with Set-Cookie headers\n const response = await this.auth.api.signUpEmail({\n body: { email, password, name: displayName },\n headers,\n asResponse: true,\n });\n\n if (!response.ok) {\n const errorData = (await response.json().catch(() => ({}))) as { message?: string };\n throw new Error(errorData.message || 'Failed to create account');\n }\n\n const result = (await response.json()) as { user?: User; token?: string | null };\n\n if (!result?.user) {\n throw new Error('Failed to create account');\n }\n\n // Extract Set-Cookie headers from Better Auth response\n const cookies: string[] = [];\n const setCookieHeader = response.headers.get('set-cookie');\n if (setCookieHeader) {\n // Split multiple cookies (they may be comma-separated or in multiple headers)\n cookies.push(...setCookieHeader.split(/,(?=\\s*\\w+=)/));\n }\n\n return {\n user: mapBetterAuthUserToEEUser(result.user),\n token: result.token ?? undefined,\n cookies,\n };\n }\n\n /**\n * Get the underlying Better Auth instance.\n * Useful for accessing Better Auth APIs directly.\n */\n getAuth(): Auth {\n return this.auth;\n }\n\n /**\n * Get headers to clear the session cookies on logout.\n * Partial ISessionProvider implementation for logout support.\n *\n * Clears Better Auth's default session cookies.\n */\n getClearSessionHeaders(): Record<string, string> {\n // Clear both the session token and its signature cookie\n const cookies = [\n `${this.sessionCookieName}=; Path=/; HttpOnly; SameSite=Lax; Max-Age=0`,\n `${this.sessionCookieName}_sig=; Path=/; HttpOnly; SameSite=Lax; Max-Age=0`,\n ];\n return {\n 'Set-Cookie': cookies.join(', '),\n };\n }\n}\n"]}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import type { IUserProvider, ICredentialsProvider, CredentialsResult } from '@mastra/core/auth';
|
|
2
|
+
import type { EEUser } from '@mastra/core/auth/ee';
|
|
3
|
+
import type { MastraAuthProviderOptions } from '@mastra/core/server';
|
|
4
|
+
import { MastraAuthProvider } from '@mastra/core/server';
|
|
5
|
+
import type { Auth, Session, User } from 'better-auth';
|
|
6
|
+
import type { HonoRequest } from 'hono';
|
|
7
|
+
/**
|
|
8
|
+
* User type returned by Better Auth session verification.
|
|
9
|
+
* Used internally for authentication token verification.
|
|
10
|
+
*/
|
|
11
|
+
export interface BetterAuthUser {
|
|
12
|
+
session: Session;
|
|
13
|
+
user: User;
|
|
14
|
+
}
|
|
15
|
+
interface MastraAuthBetterAuthOptions extends MastraAuthProviderOptions<BetterAuthUser> {
|
|
16
|
+
/**
|
|
17
|
+
* The Better Auth instance to use for authentication.
|
|
18
|
+
* This should be the result of calling `betterAuth({ ... })`.
|
|
19
|
+
*/
|
|
20
|
+
auth: Auth;
|
|
21
|
+
/**
|
|
22
|
+
* Whether to allow new user registration via sign-up.
|
|
23
|
+
* Set to false to disable public registration.
|
|
24
|
+
* @default true
|
|
25
|
+
*/
|
|
26
|
+
signUpEnabled?: boolean;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Mastra authentication provider for Better Auth.
|
|
30
|
+
*
|
|
31
|
+
* Better Auth is a self-hosted, open-source authentication framework
|
|
32
|
+
* that gives you full control over your authentication system.
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```typescript
|
|
36
|
+
* import { betterAuth } from 'better-auth';
|
|
37
|
+
* import { MastraAuthBetterAuth } from '@mastra/auth-better-auth';
|
|
38
|
+
*
|
|
39
|
+
* // Create your Better Auth instance
|
|
40
|
+
* const auth = betterAuth({
|
|
41
|
+
* database: {
|
|
42
|
+
* provider: 'postgresql',
|
|
43
|
+
* url: process.env.DATABASE_URL!,
|
|
44
|
+
* },
|
|
45
|
+
* emailAndPassword: {
|
|
46
|
+
* enabled: true,
|
|
47
|
+
* },
|
|
48
|
+
* });
|
|
49
|
+
*
|
|
50
|
+
* // Create the Mastra auth provider
|
|
51
|
+
* const mastraAuth = new MastraAuthBetterAuth({
|
|
52
|
+
* auth,
|
|
53
|
+
* });
|
|
54
|
+
*
|
|
55
|
+
* // Use with Mastra
|
|
56
|
+
* const mastra = new Mastra({
|
|
57
|
+
* server: {
|
|
58
|
+
* auth: mastraAuth,
|
|
59
|
+
* },
|
|
60
|
+
* });
|
|
61
|
+
* ```
|
|
62
|
+
*
|
|
63
|
+
* @see https://better-auth.com for Better Auth documentation
|
|
64
|
+
*/
|
|
65
|
+
export declare class MastraAuthBetterAuth extends MastraAuthProvider<BetterAuthUser> implements IUserProvider<EEUser>, ICredentialsProvider<EEUser> {
|
|
66
|
+
protected auth: Auth;
|
|
67
|
+
protected signUpEnabledConfig: boolean;
|
|
68
|
+
sessionCookieName: string;
|
|
69
|
+
constructor(options: MastraAuthBetterAuthOptions);
|
|
70
|
+
/**
|
|
71
|
+
* Check if sign-up is enabled.
|
|
72
|
+
* Implements ICredentialsProvider.isSignUpEnabled.
|
|
73
|
+
*/
|
|
74
|
+
isSignUpEnabled(): boolean;
|
|
75
|
+
/**
|
|
76
|
+
* Get current user from request.
|
|
77
|
+
* Implements IUserProvider for EE user awareness in Studio.
|
|
78
|
+
*
|
|
79
|
+
* @param request - Incoming HTTP request
|
|
80
|
+
* @returns EE User object or null if not authenticated
|
|
81
|
+
*/
|
|
82
|
+
getCurrentUser(request: Request): Promise<EEUser | null>;
|
|
83
|
+
/**
|
|
84
|
+
* Get user by ID.
|
|
85
|
+
* Implements IUserProvider for EE user awareness.
|
|
86
|
+
*
|
|
87
|
+
* Note: Better Auth doesn't expose a direct getUser API.
|
|
88
|
+
* For full functionality, you may need to implement this using
|
|
89
|
+
* direct database access in a subclass.
|
|
90
|
+
*
|
|
91
|
+
* @param userId - User identifier
|
|
92
|
+
* @returns EE User object or null if not found
|
|
93
|
+
*/
|
|
94
|
+
getUser(_userId: string): Promise<EEUser | null>;
|
|
95
|
+
/**
|
|
96
|
+
* Get URL to user's profile page.
|
|
97
|
+
* Optional IUserProvider method.
|
|
98
|
+
*/
|
|
99
|
+
getUserProfileUrl(user: EEUser): string;
|
|
100
|
+
/**
|
|
101
|
+
* Authenticate a bearer token by verifying the session with Better Auth.
|
|
102
|
+
*
|
|
103
|
+
* This method extracts the session from the request headers using
|
|
104
|
+
* Better Auth's `api.getSession()` endpoint.
|
|
105
|
+
*
|
|
106
|
+
* @param token - The bearer token (session token) to authenticate
|
|
107
|
+
* @param request - The Hono request object containing headers
|
|
108
|
+
* @returns The authenticated user and session, or null if authentication fails
|
|
109
|
+
*/
|
|
110
|
+
authenticateToken(token: string, request: HonoRequest): Promise<BetterAuthUser | null>;
|
|
111
|
+
/**
|
|
112
|
+
* Authorize a user for access.
|
|
113
|
+
*
|
|
114
|
+
* By default, any authenticated user with a valid session is authorized.
|
|
115
|
+
* You can override this behavior by providing a custom `authorizeUser` function
|
|
116
|
+
* in the constructor options.
|
|
117
|
+
*
|
|
118
|
+
* @param user - The authenticated user and session
|
|
119
|
+
* @returns True if the user is authorized, false otherwise
|
|
120
|
+
*/
|
|
121
|
+
authorizeUser(user: BetterAuthUser): Promise<boolean>;
|
|
122
|
+
/**
|
|
123
|
+
* Sign in with email and password.
|
|
124
|
+
* Implements ICredentialsProvider for EE credentials auth.
|
|
125
|
+
*
|
|
126
|
+
* @param email - User email
|
|
127
|
+
* @param password - User password
|
|
128
|
+
* @param request - Incoming HTTP request
|
|
129
|
+
* @returns Result with user and session cookies
|
|
130
|
+
* @throws Error if credentials are invalid
|
|
131
|
+
*/
|
|
132
|
+
signIn(email: string, password: string, request: Request): Promise<CredentialsResult<EEUser>>;
|
|
133
|
+
/**
|
|
134
|
+
* Sign up with email and password.
|
|
135
|
+
* Implements ICredentialsProvider for EE credentials auth.
|
|
136
|
+
*
|
|
137
|
+
* @param email - User email
|
|
138
|
+
* @param password - User password
|
|
139
|
+
* @param name - Optional display name
|
|
140
|
+
* @param request - Incoming HTTP request
|
|
141
|
+
* @returns Result with new user and session cookies
|
|
142
|
+
* @throws Error if sign up fails
|
|
143
|
+
*/
|
|
144
|
+
signUp(email: string, password: string, name: string | undefined, request: Request): Promise<CredentialsResult<EEUser>>;
|
|
145
|
+
/**
|
|
146
|
+
* Get the underlying Better Auth instance.
|
|
147
|
+
* Useful for accessing Better Auth APIs directly.
|
|
148
|
+
*/
|
|
149
|
+
getAuth(): Auth;
|
|
150
|
+
/**
|
|
151
|
+
* Get headers to clear the session cookies on logout.
|
|
152
|
+
* Partial ISessionProvider implementation for logout support.
|
|
153
|
+
*
|
|
154
|
+
* Clears Better Auth's default session cookies.
|
|
155
|
+
*/
|
|
156
|
+
getClearSessionHeaders(): Record<string, string>;
|
|
157
|
+
}
|
|
158
|
+
export {};
|
|
159
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAChG,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AACrE,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAEzD,OAAO,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,MAAM,CAAC;AAExC;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,IAAI,CAAC;CACZ;AAmBD,UAAU,2BAA4B,SAAQ,yBAAyB,CAAC,cAAc,CAAC;IACrF;;;OAGG;IACH,IAAI,EAAE,IAAI,CAAC;IAEX;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,qBAAa,oBACX,SAAQ,kBAAkB,CAAC,cAAc,CACzC,YAAW,aAAa,CAAC,MAAM,CAAC,EAAE,oBAAoB,CAAC,MAAM,CAAC;IAE9D,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC;IACrB,SAAS,CAAC,mBAAmB,EAAE,OAAO,CAAC;IAChC,iBAAiB,EAAE,MAAM,CAAC;gBAErB,OAAO,EAAE,2BAA2B;IAoBhD;;;OAGG;IACH,eAAe,IAAI,OAAO;IAS1B;;;;;;OAMG;IACG,cAAc,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAa9D;;;;;;;;;;OAUG;IACG,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAWtD;;;OAGG;IACH,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAIvC;;;;;;;;;OASG;IACG,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IA0C5F;;;;;;;;;OASG;IACG,aAAa,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC;IAU3D;;;;;;;;;OASG;IACG,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAoCnG;;;;;;;;;;OAUG;IACG,MAAM,CACV,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,OAAO,EAAE,OAAO,GACf,OAAO,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAqCrC;;;OAGG;IACH,OAAO,IAAI,IAAI;IAIf;;;;;OAKG;IACH,sBAAsB,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;CAUjD"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
import { MastraAuthProvider } from '@mastra/core/server';
|
|
2
|
+
|
|
3
|
+
// src/index.ts
|
|
4
|
+
function mapBetterAuthUserToEEUser(user) {
|
|
5
|
+
return {
|
|
6
|
+
id: user.id,
|
|
7
|
+
email: user.email,
|
|
8
|
+
name: user.name,
|
|
9
|
+
avatarUrl: user.image ?? void 0,
|
|
10
|
+
metadata: {
|
|
11
|
+
emailVerified: user.emailVerified,
|
|
12
|
+
createdAt: user.createdAt,
|
|
13
|
+
updatedAt: user.updatedAt
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
var MastraAuthBetterAuth = class extends MastraAuthProvider {
|
|
18
|
+
auth;
|
|
19
|
+
signUpEnabledConfig;
|
|
20
|
+
sessionCookieName;
|
|
21
|
+
constructor(options) {
|
|
22
|
+
super({ name: options?.name ?? "better-auth" });
|
|
23
|
+
if (!options.auth) {
|
|
24
|
+
throw new Error(
|
|
25
|
+
"Better Auth instance is required. Please provide the auth option with your Better Auth instance created via betterAuth({ ... })"
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
this.auth = options.auth;
|
|
29
|
+
this.signUpEnabledConfig = options.signUpEnabled ?? true;
|
|
30
|
+
const authWithOptions = this.auth;
|
|
31
|
+
const prefix = authWithOptions.options?.advanced?.cookiePrefix ?? "better-auth";
|
|
32
|
+
this.sessionCookieName = `${prefix}.session_token`;
|
|
33
|
+
this.registerOptions(options);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Check if sign-up is enabled.
|
|
37
|
+
* Implements ICredentialsProvider.isSignUpEnabled.
|
|
38
|
+
*/
|
|
39
|
+
isSignUpEnabled() {
|
|
40
|
+
return this.signUpEnabledConfig;
|
|
41
|
+
}
|
|
42
|
+
// ============================================
|
|
43
|
+
// IUserProvider implementation (EE capability)
|
|
44
|
+
// License check happens in buildCapabilities()
|
|
45
|
+
// ============================================
|
|
46
|
+
/**
|
|
47
|
+
* Get current user from request.
|
|
48
|
+
* Implements IUserProvider for EE user awareness in Studio.
|
|
49
|
+
*
|
|
50
|
+
* @param request - Incoming HTTP request
|
|
51
|
+
* @returns EE User object or null if not authenticated
|
|
52
|
+
*/
|
|
53
|
+
async getCurrentUser(request) {
|
|
54
|
+
try {
|
|
55
|
+
const result = await this.auth.api.getSession({
|
|
56
|
+
headers: request.headers
|
|
57
|
+
});
|
|
58
|
+
if (!result?.user) return null;
|
|
59
|
+
return mapBetterAuthUserToEEUser(result.user);
|
|
60
|
+
} catch {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Get user by ID.
|
|
66
|
+
* Implements IUserProvider for EE user awareness.
|
|
67
|
+
*
|
|
68
|
+
* Note: Better Auth doesn't expose a direct getUser API.
|
|
69
|
+
* For full functionality, you may need to implement this using
|
|
70
|
+
* direct database access in a subclass.
|
|
71
|
+
*
|
|
72
|
+
* @param userId - User identifier
|
|
73
|
+
* @returns EE User object or null if not found
|
|
74
|
+
*/
|
|
75
|
+
async getUser(_userId) {
|
|
76
|
+
console.warn(
|
|
77
|
+
"[MastraAuthBetterAuth] getUser() requires direct database access. Override this method in a subclass for full user lookup support."
|
|
78
|
+
);
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Get URL to user's profile page.
|
|
83
|
+
* Optional IUserProvider method.
|
|
84
|
+
*/
|
|
85
|
+
getUserProfileUrl(user) {
|
|
86
|
+
return `/profile/${user.id}`;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Authenticate a bearer token by verifying the session with Better Auth.
|
|
90
|
+
*
|
|
91
|
+
* This method extracts the session from the request headers using
|
|
92
|
+
* Better Auth's `api.getSession()` endpoint.
|
|
93
|
+
*
|
|
94
|
+
* @param token - The bearer token (session token) to authenticate
|
|
95
|
+
* @param request - The Hono request object containing headers
|
|
96
|
+
* @returns The authenticated user and session, or null if authentication fails
|
|
97
|
+
*/
|
|
98
|
+
async authenticateToken(token, request) {
|
|
99
|
+
try {
|
|
100
|
+
const headers = new Headers();
|
|
101
|
+
const rawRequest = "raw" in request ? request.raw : request;
|
|
102
|
+
const cookieHeader = rawRequest.headers.get("Cookie");
|
|
103
|
+
if (cookieHeader) {
|
|
104
|
+
headers.set("Cookie", cookieHeader);
|
|
105
|
+
}
|
|
106
|
+
const hasSessionCookie = !!cookieHeader?.split(";").some((pair) => {
|
|
107
|
+
const [key] = pair.trim().split("=");
|
|
108
|
+
return key?.trim() === this.sessionCookieName;
|
|
109
|
+
});
|
|
110
|
+
if (token && !hasSessionCookie) {
|
|
111
|
+
const existingCookies = cookieHeader ? `${cookieHeader}; ` : "";
|
|
112
|
+
headers.set("Cookie", `${existingCookies}${this.sessionCookieName}=${token}`);
|
|
113
|
+
}
|
|
114
|
+
const result = await this.auth.api.getSession({
|
|
115
|
+
headers
|
|
116
|
+
});
|
|
117
|
+
if (!result || !result.session || !result.user) {
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
return {
|
|
121
|
+
session: result.session,
|
|
122
|
+
user: result.user
|
|
123
|
+
};
|
|
124
|
+
} catch {
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Authorize a user for access.
|
|
130
|
+
*
|
|
131
|
+
* By default, any authenticated user with a valid session is authorized.
|
|
132
|
+
* You can override this behavior by providing a custom `authorizeUser` function
|
|
133
|
+
* in the constructor options.
|
|
134
|
+
*
|
|
135
|
+
* @param user - The authenticated user and session
|
|
136
|
+
* @returns True if the user is authorized, false otherwise
|
|
137
|
+
*/
|
|
138
|
+
async authorizeUser(user) {
|
|
139
|
+
return !!user?.session?.id && !!user?.user?.id;
|
|
140
|
+
}
|
|
141
|
+
// ============================================
|
|
142
|
+
// ICredentialsProvider implementation (EE capability)
|
|
143
|
+
// License check happens in buildCapabilities()
|
|
144
|
+
// ============================================
|
|
145
|
+
/**
|
|
146
|
+
* Sign in with email and password.
|
|
147
|
+
* Implements ICredentialsProvider for EE credentials auth.
|
|
148
|
+
*
|
|
149
|
+
* @param email - User email
|
|
150
|
+
* @param password - User password
|
|
151
|
+
* @param request - Incoming HTTP request
|
|
152
|
+
* @returns Result with user and session cookies
|
|
153
|
+
* @throws Error if credentials are invalid
|
|
154
|
+
*/
|
|
155
|
+
async signIn(email, password, request) {
|
|
156
|
+
const headers = request?.headers ?? new Headers();
|
|
157
|
+
const response = await this.auth.api.signInEmail({
|
|
158
|
+
body: { email, password },
|
|
159
|
+
headers,
|
|
160
|
+
asResponse: true
|
|
161
|
+
});
|
|
162
|
+
if (!response.ok) {
|
|
163
|
+
const errorData = await response.json().catch(() => ({}));
|
|
164
|
+
throw new Error(errorData.message || "Invalid email or password");
|
|
165
|
+
}
|
|
166
|
+
const result = await response.json();
|
|
167
|
+
if (!result?.user) {
|
|
168
|
+
throw new Error("Invalid email or password");
|
|
169
|
+
}
|
|
170
|
+
const cookies = [];
|
|
171
|
+
const setCookieHeader = response.headers.get("set-cookie");
|
|
172
|
+
if (setCookieHeader) {
|
|
173
|
+
cookies.push(...setCookieHeader.split(/,(?=\s*\w+=)/));
|
|
174
|
+
}
|
|
175
|
+
return {
|
|
176
|
+
user: mapBetterAuthUserToEEUser(result.user),
|
|
177
|
+
token: result.token ?? void 0,
|
|
178
|
+
cookies
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Sign up with email and password.
|
|
183
|
+
* Implements ICredentialsProvider for EE credentials auth.
|
|
184
|
+
*
|
|
185
|
+
* @param email - User email
|
|
186
|
+
* @param password - User password
|
|
187
|
+
* @param name - Optional display name
|
|
188
|
+
* @param request - Incoming HTTP request
|
|
189
|
+
* @returns Result with new user and session cookies
|
|
190
|
+
* @throws Error if sign up fails
|
|
191
|
+
*/
|
|
192
|
+
async signUp(email, password, name, request) {
|
|
193
|
+
const displayName = name ?? email.split("@")[0] ?? "User";
|
|
194
|
+
const headers = request?.headers ?? new Headers();
|
|
195
|
+
const response = await this.auth.api.signUpEmail({
|
|
196
|
+
body: { email, password, name: displayName },
|
|
197
|
+
headers,
|
|
198
|
+
asResponse: true
|
|
199
|
+
});
|
|
200
|
+
if (!response.ok) {
|
|
201
|
+
const errorData = await response.json().catch(() => ({}));
|
|
202
|
+
throw new Error(errorData.message || "Failed to create account");
|
|
203
|
+
}
|
|
204
|
+
const result = await response.json();
|
|
205
|
+
if (!result?.user) {
|
|
206
|
+
throw new Error("Failed to create account");
|
|
207
|
+
}
|
|
208
|
+
const cookies = [];
|
|
209
|
+
const setCookieHeader = response.headers.get("set-cookie");
|
|
210
|
+
if (setCookieHeader) {
|
|
211
|
+
cookies.push(...setCookieHeader.split(/,(?=\s*\w+=)/));
|
|
212
|
+
}
|
|
213
|
+
return {
|
|
214
|
+
user: mapBetterAuthUserToEEUser(result.user),
|
|
215
|
+
token: result.token ?? void 0,
|
|
216
|
+
cookies
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Get the underlying Better Auth instance.
|
|
221
|
+
* Useful for accessing Better Auth APIs directly.
|
|
222
|
+
*/
|
|
223
|
+
getAuth() {
|
|
224
|
+
return this.auth;
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Get headers to clear the session cookies on logout.
|
|
228
|
+
* Partial ISessionProvider implementation for logout support.
|
|
229
|
+
*
|
|
230
|
+
* Clears Better Auth's default session cookies.
|
|
231
|
+
*/
|
|
232
|
+
getClearSessionHeaders() {
|
|
233
|
+
const cookies = [
|
|
234
|
+
`${this.sessionCookieName}=; Path=/; HttpOnly; SameSite=Lax; Max-Age=0`,
|
|
235
|
+
`${this.sessionCookieName}_sig=; Path=/; HttpOnly; SameSite=Lax; Max-Age=0`
|
|
236
|
+
];
|
|
237
|
+
return {
|
|
238
|
+
"Set-Cookie": cookies.join(", ")
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
export { MastraAuthBetterAuth };
|
|
244
|
+
//# sourceMappingURL=index.js.map
|
|
245
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type { IUserProvider, ICredentialsProvider, CredentialsResult } from '@mastra/core/auth';\nimport type { EEUser } from '@mastra/core/auth/ee';\nimport type { MastraAuthProviderOptions } from '@mastra/core/server';\nimport { MastraAuthProvider } from '@mastra/core/server';\n\nimport type { Auth, Session, User } from 'better-auth';\nimport type { HonoRequest } from 'hono';\n\n/**\n * User type returned by Better Auth session verification.\n * Used internally for authentication token verification.\n */\nexport interface BetterAuthUser {\n session: Session;\n user: User;\n}\n\n/**\n * Maps Better Auth User to EE User format.\n */\nfunction mapBetterAuthUserToEEUser(user: User): EEUser {\n return {\n id: user.id,\n email: user.email,\n name: user.name,\n avatarUrl: user.image ?? undefined,\n metadata: {\n emailVerified: user.emailVerified,\n createdAt: user.createdAt,\n updatedAt: user.updatedAt,\n },\n };\n}\n\ninterface MastraAuthBetterAuthOptions extends MastraAuthProviderOptions<BetterAuthUser> {\n /**\n * The Better Auth instance to use for authentication.\n * This should be the result of calling `betterAuth({ ... })`.\n */\n auth: Auth;\n\n /**\n * Whether to allow new user registration via sign-up.\n * Set to false to disable public registration.\n * @default true\n */\n signUpEnabled?: boolean;\n}\n\n/**\n * Mastra authentication provider for Better Auth.\n *\n * Better Auth is a self-hosted, open-source authentication framework\n * that gives you full control over your authentication system.\n *\n * @example\n * ```typescript\n * import { betterAuth } from 'better-auth';\n * import { MastraAuthBetterAuth } from '@mastra/auth-better-auth';\n *\n * // Create your Better Auth instance\n * const auth = betterAuth({\n * database: {\n * provider: 'postgresql',\n * url: process.env.DATABASE_URL!,\n * },\n * emailAndPassword: {\n * enabled: true,\n * },\n * });\n *\n * // Create the Mastra auth provider\n * const mastraAuth = new MastraAuthBetterAuth({\n * auth,\n * });\n *\n * // Use with Mastra\n * const mastra = new Mastra({\n * server: {\n * auth: mastraAuth,\n * },\n * });\n * ```\n *\n * @see https://better-auth.com for Better Auth documentation\n */\nexport class MastraAuthBetterAuth\n extends MastraAuthProvider<BetterAuthUser>\n implements IUserProvider<EEUser>, ICredentialsProvider<EEUser>\n{\n protected auth: Auth;\n protected signUpEnabledConfig: boolean;\n public sessionCookieName: string;\n\n constructor(options: MastraAuthBetterAuthOptions) {\n super({ name: options?.name ?? 'better-auth' });\n\n if (!options.auth) {\n throw new Error(\n 'Better Auth instance is required. Please provide the auth option with your Better Auth instance created via betterAuth({ ... })',\n );\n }\n\n this.auth = options.auth;\n this.signUpEnabledConfig = options.signUpEnabled ?? true;\n\n // Derive the session cookie name from Better Auth's cookiePrefix option\n const authWithOptions = this.auth as unknown as { options?: { advanced?: { cookiePrefix?: string } } };\n const prefix = authWithOptions.options?.advanced?.cookiePrefix ?? 'better-auth';\n this.sessionCookieName = `${prefix}.session_token`;\n\n this.registerOptions(options);\n }\n\n /**\n * Check if sign-up is enabled.\n * Implements ICredentialsProvider.isSignUpEnabled.\n */\n isSignUpEnabled(): boolean {\n return this.signUpEnabledConfig;\n }\n\n // ============================================\n // IUserProvider implementation (EE capability)\n // License check happens in buildCapabilities()\n // ============================================\n\n /**\n * Get current user from request.\n * Implements IUserProvider for EE user awareness in Studio.\n *\n * @param request - Incoming HTTP request\n * @returns EE User object or null if not authenticated\n */\n async getCurrentUser(request: Request): Promise<EEUser | null> {\n try {\n const result = await this.auth.api.getSession({\n headers: request.headers,\n });\n\n if (!result?.user) return null;\n return mapBetterAuthUserToEEUser(result.user);\n } catch {\n return null;\n }\n }\n\n /**\n * Get user by ID.\n * Implements IUserProvider for EE user awareness.\n *\n * Note: Better Auth doesn't expose a direct getUser API.\n * For full functionality, you may need to implement this using\n * direct database access in a subclass.\n *\n * @param userId - User identifier\n * @returns EE User object or null if not found\n */\n async getUser(_userId: string): Promise<EEUser | null> {\n // Better Auth doesn't have a direct getUser API\n // Users can override this method with their own implementation\n // that queries the database directly\n console.warn(\n '[MastraAuthBetterAuth] getUser() requires direct database access. ' +\n 'Override this method in a subclass for full user lookup support.',\n );\n return null;\n }\n\n /**\n * Get URL to user's profile page.\n * Optional IUserProvider method.\n */\n getUserProfileUrl(user: EEUser): string {\n return `/profile/${user.id}`;\n }\n\n /**\n * Authenticate a bearer token by verifying the session with Better Auth.\n *\n * This method extracts the session from the request headers using\n * Better Auth's `api.getSession()` endpoint.\n *\n * @param token - The bearer token (session token) to authenticate\n * @param request - The Hono request object containing headers\n * @returns The authenticated user and session, or null if authentication fails\n */\n async authenticateToken(token: string, request: HonoRequest): Promise<BetterAuthUser | null> {\n try {\n // Better Auth's api.getSession() reads session tokens from the Cookie header\n const headers = new Headers();\n\n // The auth middleware may pass a raw Request (c.req.raw) instead of HonoRequest,\n // so unwrap via 'raw' property detection and use the standard Web API.\n const rawRequest: Request = 'raw' in request ? (request as any).raw : (request as unknown as Request);\n\n const cookieHeader = rawRequest.headers.get('Cookie');\n if (cookieHeader) {\n headers.set('Cookie', cookieHeader);\n }\n\n // Convert Bearer token to a session cookie if not already present.\n // better-auth ignores the Authorization header — it only reads from Cookie.\n const hasSessionCookie = !!cookieHeader?.split(';').some(pair => {\n const [key] = pair.trim().split('=');\n return key?.trim() === this.sessionCookieName;\n });\n if (token && !hasSessionCookie) {\n const existingCookies = cookieHeader ? `${cookieHeader}; ` : '';\n headers.set('Cookie', `${existingCookies}${this.sessionCookieName}=${token}`);\n }\n\n const result = await this.auth.api.getSession({\n headers,\n });\n\n if (!result || !result.session || !result.user) {\n return null;\n }\n\n return {\n session: result.session,\n user: result.user,\n };\n } catch {\n return null;\n }\n }\n\n /**\n * Authorize a user for access.\n *\n * By default, any authenticated user with a valid session is authorized.\n * You can override this behavior by providing a custom `authorizeUser` function\n * in the constructor options.\n *\n * @param user - The authenticated user and session\n * @returns True if the user is authorized, false otherwise\n */\n async authorizeUser(user: BetterAuthUser): Promise<boolean> {\n // By default, any authenticated user with a valid session is authorized\n return !!user?.session?.id && !!user?.user?.id;\n }\n\n // ============================================\n // ICredentialsProvider implementation (EE capability)\n // License check happens in buildCapabilities()\n // ============================================\n\n /**\n * Sign in with email and password.\n * Implements ICredentialsProvider for EE credentials auth.\n *\n * @param email - User email\n * @param password - User password\n * @param request - Incoming HTTP request\n * @returns Result with user and session cookies\n * @throws Error if credentials are invalid\n */\n async signIn(email: string, password: string, request: Request): Promise<CredentialsResult<EEUser>> {\n const headers = request?.headers ?? new Headers();\n\n // Use asResponse: true to get the full response with Set-Cookie headers\n const response = await this.auth.api.signInEmail({\n body: { email, password },\n headers,\n asResponse: true,\n });\n\n if (!response.ok) {\n const errorData = (await response.json().catch(() => ({}))) as { message?: string };\n throw new Error(errorData.message || 'Invalid email or password');\n }\n\n const result = (await response.json()) as { user?: User; token?: string | null };\n\n if (!result?.user) {\n throw new Error('Invalid email or password');\n }\n\n // Extract Set-Cookie headers from Better Auth response\n const cookies: string[] = [];\n const setCookieHeader = response.headers.get('set-cookie');\n if (setCookieHeader) {\n // Split multiple cookies (they may be comma-separated or in multiple headers)\n cookies.push(...setCookieHeader.split(/,(?=\\s*\\w+=)/));\n }\n\n return {\n user: mapBetterAuthUserToEEUser(result.user),\n token: result.token ?? undefined,\n cookies,\n };\n }\n\n /**\n * Sign up with email and password.\n * Implements ICredentialsProvider for EE credentials auth.\n *\n * @param email - User email\n * @param password - User password\n * @param name - Optional display name\n * @param request - Incoming HTTP request\n * @returns Result with new user and session cookies\n * @throws Error if sign up fails\n */\n async signUp(\n email: string,\n password: string,\n name: string | undefined,\n request: Request,\n ): Promise<CredentialsResult<EEUser>> {\n const displayName = name ?? email.split('@')[0] ?? 'User';\n const headers = request?.headers ?? new Headers();\n\n // Use asResponse: true to get the full response with Set-Cookie headers\n const response = await this.auth.api.signUpEmail({\n body: { email, password, name: displayName },\n headers,\n asResponse: true,\n });\n\n if (!response.ok) {\n const errorData = (await response.json().catch(() => ({}))) as { message?: string };\n throw new Error(errorData.message || 'Failed to create account');\n }\n\n const result = (await response.json()) as { user?: User; token?: string | null };\n\n if (!result?.user) {\n throw new Error('Failed to create account');\n }\n\n // Extract Set-Cookie headers from Better Auth response\n const cookies: string[] = [];\n const setCookieHeader = response.headers.get('set-cookie');\n if (setCookieHeader) {\n // Split multiple cookies (they may be comma-separated or in multiple headers)\n cookies.push(...setCookieHeader.split(/,(?=\\s*\\w+=)/));\n }\n\n return {\n user: mapBetterAuthUserToEEUser(result.user),\n token: result.token ?? undefined,\n cookies,\n };\n }\n\n /**\n * Get the underlying Better Auth instance.\n * Useful for accessing Better Auth APIs directly.\n */\n getAuth(): Auth {\n return this.auth;\n }\n\n /**\n * Get headers to clear the session cookies on logout.\n * Partial ISessionProvider implementation for logout support.\n *\n * Clears Better Auth's default session cookies.\n */\n getClearSessionHeaders(): Record<string, string> {\n // Clear both the session token and its signature cookie\n const cookies = [\n `${this.sessionCookieName}=; Path=/; HttpOnly; SameSite=Lax; Max-Age=0`,\n `${this.sessionCookieName}_sig=; Path=/; HttpOnly; SameSite=Lax; Max-Age=0`,\n ];\n return {\n 'Set-Cookie': cookies.join(', '),\n };\n }\n}\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mastra/auth-better-auth",
|
|
3
|
+
"version": "0.0.0-agent-chat-ui-20260305212602",
|
|
4
|
+
"description": "Mastra Better Auth integration - self-hosted authentication",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"default": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"require": {
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"default": "./dist/index.cjs"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"./package.json": "./package.json"
|
|
20
|
+
},
|
|
21
|
+
"license": "Apache-2.0",
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"better-auth": "^1.4.18"
|
|
24
|
+
},
|
|
25
|
+
"peerDependencies": {
|
|
26
|
+
"@mastra/core": "0.0.0-agent-chat-ui-20260305212602"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@types/node": "22.19.7",
|
|
30
|
+
"hono": "^4.11.9",
|
|
31
|
+
"@vitest/coverage-v8": "4.0.18",
|
|
32
|
+
"@vitest/ui": "4.0.18",
|
|
33
|
+
"eslint": "^9.37.0",
|
|
34
|
+
"tsup": "^8.5.1",
|
|
35
|
+
"typescript": "^5.9.3",
|
|
36
|
+
"vitest": "4.0.18",
|
|
37
|
+
"@internal/lint": "0.0.0-agent-chat-ui-20260305212602",
|
|
38
|
+
"@mastra/core": "0.0.0-agent-chat-ui-20260305212602",
|
|
39
|
+
"@internal/types-builder": "0.0.0-agent-chat-ui-20260305212602"
|
|
40
|
+
},
|
|
41
|
+
"files": [
|
|
42
|
+
"dist",
|
|
43
|
+
"CHANGELOG.md"
|
|
44
|
+
],
|
|
45
|
+
"homepage": "https://mastra.ai",
|
|
46
|
+
"repository": {
|
|
47
|
+
"type": "git",
|
|
48
|
+
"url": "git+https://github.com/mastra-ai/mastra.git",
|
|
49
|
+
"directory": "auth/better-auth"
|
|
50
|
+
},
|
|
51
|
+
"bugs": {
|
|
52
|
+
"url": "https://github.com/mastra-ai/mastra/issues"
|
|
53
|
+
},
|
|
54
|
+
"engines": {
|
|
55
|
+
"node": ">=22.13.0"
|
|
56
|
+
},
|
|
57
|
+
"scripts": {
|
|
58
|
+
"build": "tsup --silent --config tsup.config.ts",
|
|
59
|
+
"build:watch": "tsup --watch --silent --config tsup.config.ts",
|
|
60
|
+
"test": "vitest run",
|
|
61
|
+
"lint": "eslint ."
|
|
62
|
+
}
|
|
63
|
+
}
|