@momentumcms/auth 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -0
- package/CLAUDE.md +130 -0
- package/LICENSE +21 -0
- package/README.md +11 -0
- package/index.cjs +1227 -0
- package/package.json +37 -0
- package/src/index.d.ts +10 -0
- package/src/lib/auth-collections.d.ts +27 -0
- package/src/lib/auth-plugin.d.ts +79 -0
- package/src/lib/auth.d.ts +144 -0
- package/src/lib/email-templates.d.ts +48 -0
- package/src/lib/email.d.ts +72 -0
- package/src/lib/plugins/admin.d.ts +19 -0
- package/src/lib/plugins/index.d.ts +4 -0
- package/src/lib/plugins/organization.d.ts +19 -0
- package/src/lib/plugins/sub-plugin.types.d.ts +29 -0
- package/src/lib/plugins/two-factor.d.ts +12 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
## 0.1.0 (2026-02-16)
|
|
2
|
+
|
|
3
|
+
### 🚀 Features
|
|
4
|
+
|
|
5
|
+
- add password reset flow with E2E tests ([#6](https://github.com/DonaldMurillo/momentum-cms/pull/6))
|
|
6
|
+
- **ui:** enhance command palette with autofocus, filtering, and keyboard nav ([#2](https://github.com/DonaldMurillo/momentum-cms/pull/2))
|
|
7
|
+
- Add authentication, UI library, and theme system ([0d38720](https://github.com/DonaldMurillo/momentum-cms/commit/0d38720))
|
|
8
|
+
- Implement admin UI with API integration and SSR hydration ([9ed7b2b](https://github.com/DonaldMurillo/momentum-cms/commit/9ed7b2b))
|
|
9
|
+
- Initialize Momentum CMS foundation ([f64f581](https://github.com/DonaldMurillo/momentum-cms/commit/f64f581))
|
|
10
|
+
|
|
11
|
+
### 🩹 Fixes
|
|
12
|
+
|
|
13
|
+
- address security vulnerabilities from code review ([#9](https://github.com/DonaldMurillo/momentum-cms/pull/9))
|
|
14
|
+
|
|
15
|
+
### ❤️ Thank You
|
|
16
|
+
|
|
17
|
+
- Claude Opus 4.5
|
|
18
|
+
- Claude Opus 4.6
|
|
19
|
+
- Donald Murillo @DonaldMurillo
|
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# Auth Library (`@momentumcms/auth`)
|
|
2
|
+
|
|
3
|
+
Better Auth integration for Momentum CMS. Plugin-based architecture that manages auth collections, session resolution, and sub-plugin composition.
|
|
4
|
+
|
|
5
|
+
## Architecture Overview
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
momentumAuth(config) ← Plugin factory (auth-plugin.ts)
|
|
9
|
+
├── BASE_AUTH_COLLECTIONS ← 5 auth collections (auth-collections.ts)
|
|
10
|
+
├── createMomentumAuth() ← Better Auth instance (auth.ts)
|
|
11
|
+
└── sub-plugins[] ← Composable extensions (plugins/)
|
|
12
|
+
├── authTwoFactor()
|
|
13
|
+
├── authAdmin()
|
|
14
|
+
└── authOrganization()
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
### Key Files
|
|
18
|
+
|
|
19
|
+
| File | Purpose |
|
|
20
|
+
| ----------------------------- | ---------------------------------------------------------------------- |
|
|
21
|
+
| `auth-plugin.ts` | `momentumAuth()` factory — creates the `MomentumPlugin` |
|
|
22
|
+
| `auth.ts` | `createMomentumAuth()` — wraps `betterAuth()` with Momentum defaults |
|
|
23
|
+
| `auth-collections.ts` | Base auth collections (user, session, account, verification, api-keys) |
|
|
24
|
+
| `plugins/sub-plugin.types.ts` | `MomentumAuthSubPlugin` interface |
|
|
25
|
+
| `plugins/two-factor.ts` | Example sub-plugin pattern |
|
|
26
|
+
|
|
27
|
+
### Plugin Lifecycle
|
|
28
|
+
|
|
29
|
+
1. `momentumAuth(config)` is called at config time — collects sub-plugin collections/fields
|
|
30
|
+
2. `plugin.collections` is read by admin routes for static route data (browser-safe)
|
|
31
|
+
3. `plugin.onInit(context)` runs during server init — injects collections, creates Better Auth instance
|
|
32
|
+
4. `initializeMomentum()` in server-express detects the auth plugin, auto-creates middleware
|
|
33
|
+
|
|
34
|
+
## Collection Slugs and DB Tables
|
|
35
|
+
|
|
36
|
+
Auth collections use `auth-` prefixed slugs to avoid conflicts with user-defined collections.
|
|
37
|
+
|
|
38
|
+
| Slug | DB Table | Sidebar | Access |
|
|
39
|
+
| ------------------- | -------------- | --------------------------- | --------------------------------------------------- |
|
|
40
|
+
| `auth-user` | `user` | Yes (group: Authentication) | Admin only (read/write) |
|
|
41
|
+
| `auth-session` | `session` | No (hidden) | Admin read, no write |
|
|
42
|
+
| `auth-account` | `account` | No (hidden) | No read (contains OAuth tokens/passwords), no write |
|
|
43
|
+
| `auth-verification` | `verification` | No (hidden) | No access |
|
|
44
|
+
| `auth-api-keys` | `_api_keys` | Yes (group: Authentication) | Any authenticated user (scoped by `defaultWhere`) |
|
|
45
|
+
|
|
46
|
+
Internal collections (`auth-session`, `auth-account`, `auth-verification`) are `managed: true` — the API blocks write operations (POST/PATCH/DELETE return 403). Better Auth owns the data. `auth-user` and `auth-api-keys` are NOT managed: `auth-user` allows admin CRUD, `auth-api-keys` blocks writes via access control and routes deletion through the dedicated `/api/auth/api-keys/:id` endpoint with ownership checks.
|
|
47
|
+
|
|
48
|
+
## Critical: Session and Role Handling
|
|
49
|
+
|
|
50
|
+
### No Cookie Cache
|
|
51
|
+
|
|
52
|
+
The Better Auth session config intentionally has **no `cookieCache`**. This was removed because:
|
|
53
|
+
|
|
54
|
+
- Cookie cache stores session data (including `role`) in a signed cookie
|
|
55
|
+
- When a user's role changes (e.g., setup flow creates admin), the cached cookie retains the stale role
|
|
56
|
+
- All subsequent requests read stale `role: 'user'` from the cookie instead of `role: 'admin'` from the DB
|
|
57
|
+
- This causes auth collection access checks (`req.user?.role === 'admin'`) to fail with 403
|
|
58
|
+
|
|
59
|
+
**Never re-enable `cookieCache`** unless you also solve stale role propagation (e.g., invalidate sessions on role change).
|
|
60
|
+
|
|
61
|
+
### Role Update Flow
|
|
62
|
+
|
|
63
|
+
The setup flow (`POST /setup/create-admin`) does:
|
|
64
|
+
|
|
65
|
+
1. `auth.api.signUpEmail()` — creates user with `role: 'user'` (Better Auth default)
|
|
66
|
+
2. `updateUserRolePostgres()` — SQL update to set `role: 'admin'`
|
|
67
|
+
|
|
68
|
+
The role column is an `additionalFields` entry in Better Auth's user config, not a native field. Better Auth reads it from the DB on every `getSession()` call (since there's no cookie cache), so role changes take effect immediately.
|
|
69
|
+
|
|
70
|
+
### Seeding and `onConflict: 'skip'`
|
|
71
|
+
|
|
72
|
+
Seeds use `authUser()` helper which calls `signUpEmail()` + `adapter.update()` for role. But seeds are tracked by `seedId` — if the seed was already processed, `onConflict: 'skip'` returns early **without updating the role**. This means:
|
|
73
|
+
|
|
74
|
+
- Changing a seed's `role` from `'user'` to `'admin'` has no effect on existing databases
|
|
75
|
+
- You must either: (a) delete the `_seed_tracking` row for that seed, (b) use a new seedId, or (c) update the role via direct SQL
|
|
76
|
+
|
|
77
|
+
## Sub-Plugin Pattern
|
|
78
|
+
|
|
79
|
+
Sub-plugins extend auth without modifying the core. Each sub-plugin provides:
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
export interface MomentumAuthSubPlugin {
|
|
83
|
+
name: string; // For logging
|
|
84
|
+
betterAuthPlugin: unknown; // The Better Auth plugin instance
|
|
85
|
+
collections?: CollectionConfig[]; // Managed collections to inject
|
|
86
|
+
userFields?: Field[]; // Fields to add to auth-user
|
|
87
|
+
sessionFields?: Field[]; // Fields to add to auth-session
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Creating a Sub-Plugin
|
|
92
|
+
|
|
93
|
+
Follow the `two-factor.ts` pattern:
|
|
94
|
+
|
|
95
|
+
1. Create `plugins/my-plugin.ts`
|
|
96
|
+
2. Define any managed collections with `defineCollection({ managed: true, ... })`
|
|
97
|
+
3. Export a factory function returning `MomentumAuthSubPlugin`
|
|
98
|
+
4. Use `admin: { hidden: true }` for internal collections users shouldn't see
|
|
99
|
+
5. Set restrictive `access` rules — most auth data shouldn't be directly accessible
|
|
100
|
+
|
|
101
|
+
### Sub-Plugin Collection Rules
|
|
102
|
+
|
|
103
|
+
- Use `auth-` prefix for slugs (e.g., `auth-two-factor`)
|
|
104
|
+
- Set `dbName` to match Better Auth's expected table name
|
|
105
|
+
- Always set `managed: true` — Better Auth owns the data
|
|
106
|
+
- Match field definitions exactly to Better Auth's schema
|
|
107
|
+
|
|
108
|
+
## Browser-Safe Imports
|
|
109
|
+
|
|
110
|
+
The auth-collections are importable in browser code via:
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
import { BASE_AUTH_COLLECTIONS } from '@momentumcms/auth/collections';
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
This path alias (`tsconfig.base.json`) points to `auth-collections.ts`, which only imports from `@momentumcms/core` (no Node.js dependencies). This is used by `momentumAdminRoutes()` for static route generation.
|
|
117
|
+
|
|
118
|
+
**Never add Node.js imports** (pg, better-auth, etc.) to `auth-collections.ts`.
|
|
119
|
+
|
|
120
|
+
## Common Pitfalls
|
|
121
|
+
|
|
122
|
+
1. **403 on auth collections after role change**: Role is stale. Check `req.user.role` — if it's `'user'` when it should be `'admin'`, the DB role wasn't updated or the session is stale. Clear cookies and re-login, or check the DB directly.
|
|
123
|
+
|
|
124
|
+
2. **Seed doesn't update role**: Seeds with `onConflict: 'skip'` won't re-process. See "Seeding and onConflict" above.
|
|
125
|
+
|
|
126
|
+
3. **New sub-plugin fields not appearing**: Better Auth needs the field in `additionalFields`. The plugin factory merges `userFields` into the auth config automatically — make sure the sub-plugin returns them.
|
|
127
|
+
|
|
128
|
+
4. **Collection slug vs DB table name**: Auth collections use `auth-user` as the slug (for API routes, admin UI) but `user` as the DB table (`dbName`). The Drizzle adapter's `resolveTableName()` handles the mapping. Don't use raw table names in API calls.
|
|
129
|
+
|
|
130
|
+
5. **E2E tests and role timing**: E2E fixtures use `signUpEmail()` + direct DB role update + fresh `signIn()`. The separate sign-in ensures the new session reads the correct role. Don't rely on the session from `signUpEmail()` after a role change.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024-present Momentum CMS Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|