@aotter/mantle 0.1.2-alpha.5 → 0.1.2-alpha.6
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.
|
@@ -177,8 +177,10 @@ const auth = createAuth({
|
|
|
177
177
|
{
|
|
178
178
|
kind: "social",
|
|
179
179
|
provider: "github",
|
|
180
|
-
|
|
181
|
-
|
|
180
|
+
options: {
|
|
181
|
+
clientId: env.GITHUB_CLIENT_ID,
|
|
182
|
+
clientSecret: env.GITHUB_CLIENT_SECRET,
|
|
183
|
+
},
|
|
182
184
|
},
|
|
183
185
|
],
|
|
184
186
|
bootstrapOwner: env.ADMIN_GITHUB_LOGIN
|
|
@@ -734,3 +734,24 @@ one-way hashes. This is a fixed security boundary, not adopter configuration;
|
|
|
734
734
|
Deploying this change invalidates any unconsumed codes and links created by an
|
|
735
735
|
older deployment. Users request a new code or link; no database migration is
|
|
736
736
|
needed.
|
|
737
|
+
|
|
738
|
+
## 2026-09-18 amendment — native Better Auth method options
|
|
739
|
+
|
|
740
|
+
Issue #924 supersedes only the preceding amendment's “not adopter
|
|
741
|
+
configuration” restriction. Hashed OTP and magic-link storage remains the
|
|
742
|
+
Mantle default, while an explicit official Better Auth `storeOTP` or
|
|
743
|
+
`storeToken` option may override it, including custom hashers/encryption.
|
|
744
|
+
|
|
745
|
+
`createAuth` remains the Worker lifecycle and Mantle integration boundary, but
|
|
746
|
+
does not copy Better Auth's method option unions. Social methods use the
|
|
747
|
+
provider-specific official `SocialProviders` option keyed by `provider`,
|
|
748
|
+
including async factories. Generic OAuth uses `GenericOAuthConfig`; email OTP
|
|
749
|
+
and magic link use their official option types minus the sender callback that
|
|
750
|
+
Mantle owns. GitHub's bootstrap mapper composes with an adopter mapper instead
|
|
751
|
+
of replacing it. Admin method metadata contains only kind, provider id and
|
|
752
|
+
display label, never options or secrets.
|
|
753
|
+
|
|
754
|
+
Applications that need to own an entire callback may pass official plugin
|
|
755
|
+
instances through `plugins`. Those plugins do not synthesize Admin metadata,
|
|
756
|
+
and duplicate plugin ids fail at construction. There is no
|
|
757
|
+
`Partial<BetterAuthOptions>` deep merge and no silent plugin replacement.
|
package/docs/adr/README.md
CHANGED
|
@@ -15,7 +15,7 @@ Records of *why* mantle ended up shaped this way. The numbering preserves POC AD
|
|
|
15
15
|
| [0011](0011-adapter-port-spec.md) | Adapter port spec. Required runtime ports plus optional feature ports. | Accepted (new) |
|
|
16
16
|
| [0012](0012-views-as-public-rest.md) | Views auto-expose matching REST and `query_view_*` MCP reads on their declared `public` or `staff` surface. Schemas never get a public REST endpoint. | Accepted + amended |
|
|
17
17
|
| [0013](0013-agent-provisioned-consumer-projects.md) | Historical agent-provisioned consumer projects path. Superseded for first launch by landing provision bundles. | Superseded |
|
|
18
|
-
| [0014](0014-auth-better-auth-and-multi-tenant-mcp.md) | The Cloudflare adapter owns one
|
|
18
|
+
| [0014](0014-auth-better-auth-and-multi-tenant-mcp.md) | The Cloudflare adapter owns one Better Auth 1.7 identity/OAuth/MCP authority with native method options and CIMD discovery. Verified callers are normalized into runtime context; mutable staff role and target authorization are re-evaluated per call. | Accepted + amended |
|
|
19
19
|
| [0016](0016-site-semantic-layer.md) | Site semantic layer: `AGENTS.md` (cross-tool entry) + `.mantle/launch-state.json` (deterministic install context). The older `mantle/site.md` letter surface is suspended from first-run scaffolds. | Accepted (slimmed) |
|
|
20
20
|
| [0017](0017-media-multi-variant-agent-side-optimization.md) | Multi-variant media assets with agent-side optimization and asset-id entry references. | Accepted |
|
|
21
21
|
| [0018](0018-core-starters-repository-boundary.md) | Core produces published SDK artifacts; the separate starters repository validates them as an external consumer. Revisit after release-contract simplification. | Superseded by 0021 |
|
|
@@ -23,11 +23,11 @@ A free Mantle site can run every login method the SDK exposes through
|
|
|
23
23
|
`createAuth()`:
|
|
24
24
|
|
|
25
25
|
- social OAuth providers supported by Better Auth;
|
|
26
|
-
-
|
|
26
|
+
- provider-specific options through Better Auth's native `socialProviders` types;
|
|
27
27
|
- email OTP;
|
|
28
28
|
- magic link;
|
|
29
|
-
- passkey or
|
|
30
|
-
|
|
29
|
+
- passkey or another Better Auth method through the raw `plugins` path when the
|
|
30
|
+
application owns its callback and UI;
|
|
31
31
|
- first-party same-domain or same-parent-domain SSO when the site owner
|
|
32
32
|
controls every participating subdomain.
|
|
33
33
|
|
|
@@ -143,9 +143,9 @@ the exact public API and four consumer examples.
|
|
|
143
143
|
|
|
144
144
|
## SDK Surface Rule
|
|
145
145
|
|
|
146
|
-
Mantle
|
|
147
|
-
|
|
148
|
-
|
|
146
|
+
Mantle owns only integration fields with a real Mantle use case. Method
|
|
147
|
+
configuration uses Better Auth's official provider/plugin option types; do not
|
|
148
|
+
copy those unions or add a generic `Partial<BetterAuthOptions>` deep merge.
|
|
149
149
|
|
|
150
150
|
The current first-party SSO use case justifies these optional fields on
|
|
151
151
|
`CreateAuthConfig`:
|
|
@@ -154,14 +154,13 @@ The current first-party SSO use case justifies these optional fields on
|
|
|
154
154
|
- `crossSubDomainCookies`
|
|
155
155
|
- `cookiePrefix`
|
|
156
156
|
|
|
157
|
-
The cross-site API use case additionally justifies these
|
|
158
|
-
facades:
|
|
157
|
+
The cross-site API use case additionally justifies these fields and facades:
|
|
159
158
|
|
|
160
|
-
- generic OAuth
|
|
159
|
+
- native generic OAuth `authorizationUrlParams`, `tokenUrlParams`, and
|
|
160
|
+
`refreshTokenParams` for RFC 8707 `resource`
|
|
161
161
|
- OAuth provider `resources` and the curated `mcpResource`
|
|
162
162
|
- `Auth.getProviderAccessToken(request, providerId)`
|
|
163
163
|
- `Auth.verifyOAuthAccessToken(tokenOrRequest, { audience, scopes })`
|
|
164
164
|
|
|
165
|
-
Generic OAuth providers use Better Auth 1.7's
|
|
166
|
-
`/api/auth/callback/:id` path.
|
|
167
|
-
passthrough.
|
|
165
|
+
Generic OAuth providers use Better Auth 1.7's official `GenericOAuthConfig`,
|
|
166
|
+
standard social sign-in and `/api/auth/callback/:id` path.
|
|
@@ -3,7 +3,7 @@ description: Configure MANTLE_AUTH_MODE, secrets, the first owner and staff role
|
|
|
3
3
|
---
|
|
4
4
|
# Authentication
|
|
5
5
|
|
|
6
|
-
Conventional Auth is chosen by one variable, `MANTLE_AUTH_MODE`, and fails closed when its configuration is incomplete. This page covers the two modes, the secrets each needs, first-owner bootstrap, roles, the routes that require a session, and the
|
|
6
|
+
Conventional Auth is chosen by one variable, `MANTLE_AUTH_MODE`, and fails closed when its configuration is incomplete. This page covers the two modes, the secrets each needs, first-owner bootstrap, roles, the routes that require a session, and the Better Auth integration surface.
|
|
7
7
|
|
|
8
8
|
## Mode matrix
|
|
9
9
|
|
|
@@ -71,9 +71,59 @@ The staff role is re-read from D1 on every protected REST and MCP call; a revoke
|
|
|
71
71
|
|
|
72
72
|
MCP tokens are session-bound: signing out of Admin ends MCP access. See [MCP and agents](../concepts/mcp-and-agents.md).
|
|
73
73
|
|
|
74
|
-
##
|
|
74
|
+
## Better Auth configuration
|
|
75
75
|
|
|
76
|
-
`createAuth()`
|
|
76
|
+
`createAuth()` owns the Worker lifecycle, Admin metadata, sender integration,
|
|
77
|
+
bootstrap rules, roles and MCP invariants. Method-specific configuration stays
|
|
78
|
+
native to Better Auth under `options`, so provider updates and type inference do
|
|
79
|
+
not need a matching Mantle DSL update. There is deliberately no
|
|
80
|
+
`Partial<BetterAuthOptions>` deep merge.
|
|
81
|
+
|
|
82
|
+
```ts
|
|
83
|
+
methods: [
|
|
84
|
+
{
|
|
85
|
+
kind: "social",
|
|
86
|
+
provider: "google",
|
|
87
|
+
options: { clientId: env.GOOGLE_CLIENT_ID, clientSecret: env.GOOGLE_CLIENT_SECRET, accessType: "offline" },
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
kind: "social",
|
|
91
|
+
provider: "apple",
|
|
92
|
+
options: async () => ({ clientId: env.APPLE_CLIENT_ID, clientSecret: await loadAppleSecret(env) }),
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
kind: "email-otp",
|
|
96
|
+
sender,
|
|
97
|
+
options: { otpLength: 8 },
|
|
98
|
+
},
|
|
99
|
+
]
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Email OTP and magic-link storage defaults to `hashed`. Explicit official
|
|
103
|
+
overrides remain available, including custom hashing/encryption:
|
|
104
|
+
|
|
105
|
+
```ts
|
|
106
|
+
{ kind: "email-otp", sender, options: {
|
|
107
|
+
storeOTP: { encrypt: encryptOtp, decrypt: decryptOtp },
|
|
108
|
+
} }
|
|
109
|
+
{ kind: "magic-link", sender, options: {
|
|
110
|
+
storeToken: { type: "custom-hasher", hash: hashMagicToken },
|
|
111
|
+
} }
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
For complete callback ownership, register an official plugin instance directly.
|
|
115
|
+
Raw plugins do not add a button to `Auth.methods`; the application owns that UI.
|
|
116
|
+
Duplicate plugin ids fail at construction rather than silently replacing one:
|
|
117
|
+
|
|
118
|
+
```ts
|
|
119
|
+
createAuth({
|
|
120
|
+
database: env.DB,
|
|
121
|
+
baseURL: env.PUBLIC_ORIGIN,
|
|
122
|
+
secret: env.BETTER_AUTH_SECRET,
|
|
123
|
+
methods: [],
|
|
124
|
+
plugins: [emailOTP({ sendVerificationOTP, storeOTP: "encrypted" })],
|
|
125
|
+
});
|
|
126
|
+
```
|
|
77
127
|
|
|
78
128
|
When several first-party apps share one parent domain that the same party controls, configure shared cookies explicitly. `cookiePrefix` is required whenever more than one Better Auth app writes cookies under that domain; `trustedOrigins` is the auth-flow trust list, not a CORS policy.
|
|
79
129
|
|
|
@@ -116,11 +166,15 @@ const clientAuth = createAuth({
|
|
|
116
166
|
// database, baseURL, secret, other methods...
|
|
117
167
|
methods: [{
|
|
118
168
|
kind: "oauth",
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
169
|
+
options: {
|
|
170
|
+
providerId: "mantle-platform",
|
|
171
|
+
clientId: env.PLATFORM_CLIENT_ID,
|
|
172
|
+
discoveryUrl: "https://platform.example.com/api/auth/.well-known/openid-configuration",
|
|
173
|
+
scopes: ["openid", "offline_access", "accounts:read"],
|
|
174
|
+
authorizationUrlParams: { resource: "https://api.example.com" },
|
|
175
|
+
tokenUrlParams: { resource: "https://api.example.com" },
|
|
176
|
+
refreshTokenParams: { resource: "https://api.example.com" },
|
|
177
|
+
},
|
|
124
178
|
}],
|
|
125
179
|
});
|
|
126
180
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aotter/mantle",
|
|
3
|
-
"version": "0.1.2-alpha.
|
|
3
|
+
"version": "0.1.2-alpha.6",
|
|
4
4
|
"description": "Embeddable Mantle Core umbrella with Spec and Runtime; Web, Admin, Bun, Vercel, Cloudflare, and Admin UI are optional peer packages.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://mantle.tools/",
|
|
@@ -79,8 +79,8 @@
|
|
|
79
79
|
"README.md"
|
|
80
80
|
],
|
|
81
81
|
"dependencies": {
|
|
82
|
-
"@aotter/mantle-runtime": "0.1.2-alpha.
|
|
83
|
-
"@aotter/mantle-spec": "0.1.2-alpha.
|
|
82
|
+
"@aotter/mantle-runtime": "0.1.2-alpha.6",
|
|
83
|
+
"@aotter/mantle-spec": "0.1.2-alpha.6"
|
|
84
84
|
},
|
|
85
85
|
"peerDependencies": {
|
|
86
86
|
"aws4fetch": "^1.0.20",
|
|
@@ -88,12 +88,12 @@
|
|
|
88
88
|
"hono": "^4.12.0",
|
|
89
89
|
"@libsql/client": "^0.17.4",
|
|
90
90
|
"zod": "^4.5.0",
|
|
91
|
-
"@aotter/mantle-admin
|
|
92
|
-
"@aotter/mantle-
|
|
93
|
-
"@aotter/mantle-
|
|
94
|
-
"@aotter/mantle-
|
|
95
|
-
"@aotter/mantle-
|
|
96
|
-
"@aotter/mantle-
|
|
91
|
+
"@aotter/mantle-admin": "0.1.2-alpha.6",
|
|
92
|
+
"@aotter/mantle-bun": "0.1.2-alpha.6",
|
|
93
|
+
"@aotter/mantle-admin-ui": "0.1.2-alpha.6",
|
|
94
|
+
"@aotter/mantle-vercel": "0.1.2-alpha.6",
|
|
95
|
+
"@aotter/mantle-cloudflare": "0.1.2-alpha.6",
|
|
96
|
+
"@aotter/mantle-web": "0.1.2-alpha.6"
|
|
97
97
|
},
|
|
98
98
|
"peerDependenciesMeta": {
|
|
99
99
|
"@aotter/mantle-admin": {
|
|
@@ -136,12 +136,12 @@
|
|
|
136
136
|
"typescript": "^6.0.3",
|
|
137
137
|
"vitest": "^4.1.11",
|
|
138
138
|
"zod": "^4.5.4",
|
|
139
|
-
"@aotter/mantle-admin
|
|
140
|
-
"@aotter/mantle-
|
|
141
|
-
"@aotter/mantle-
|
|
142
|
-
"@aotter/mantle-cloudflare": "0.1.2-alpha.
|
|
143
|
-
"@aotter/mantle-vercel": "0.1.2-alpha.
|
|
144
|
-
"@aotter/mantle-web": "0.1.2-alpha.
|
|
139
|
+
"@aotter/mantle-admin": "0.1.2-alpha.6",
|
|
140
|
+
"@aotter/mantle-admin-ui": "0.1.2-alpha.6",
|
|
141
|
+
"@aotter/mantle-bun": "0.1.2-alpha.6",
|
|
142
|
+
"@aotter/mantle-cloudflare": "0.1.2-alpha.6",
|
|
143
|
+
"@aotter/mantle-vercel": "0.1.2-alpha.6",
|
|
144
|
+
"@aotter/mantle-web": "0.1.2-alpha.6"
|
|
145
145
|
},
|
|
146
146
|
"engines": {
|
|
147
147
|
"node": ">=22"
|