clearauth 0.3.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 +235 -0
- package/LICENSE +21 -0
- package/README.md +417 -0
- package/dist/auth/handler.d.ts +38 -0
- package/dist/auth/handler.js +483 -0
- package/dist/auth/handler.js.map +1 -0
- package/dist/auth/login.d.ts +69 -0
- package/dist/auth/login.js +103 -0
- package/dist/auth/login.js.map +1 -0
- package/dist/auth/register.d.ts +72 -0
- package/dist/auth/register.js +122 -0
- package/dist/auth/register.js.map +1 -0
- package/dist/auth/reset-password.d.ts +106 -0
- package/dist/auth/reset-password.js +213 -0
- package/dist/auth/reset-password.js.map +1 -0
- package/dist/auth/utils.d.ts +58 -0
- package/dist/auth/utils.js +121 -0
- package/dist/auth/utils.js.map +1 -0
- package/dist/auth/verify-email.d.ts +70 -0
- package/dist/auth/verify-email.js +137 -0
- package/dist/auth/verify-email.js.map +1 -0
- package/dist/createMechAuth.d.ts +178 -0
- package/dist/createMechAuth.js +215 -0
- package/dist/createMechAuth.js.map +1 -0
- package/dist/database/schema.d.ts +135 -0
- package/dist/database/schema.js +37 -0
- package/dist/database/schema.js.map +1 -0
- package/dist/edge.d.ts +4 -0
- package/dist/edge.js +6 -0
- package/dist/edge.js.map +1 -0
- package/dist/errors.d.ts +25 -0
- package/dist/errors.js +44 -0
- package/dist/errors.js.map +1 -0
- package/dist/handler.d.ts +100 -0
- package/dist/handler.js +213 -0
- package/dist/handler.js.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.js +28 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +22 -0
- package/dist/logger.js +40 -0
- package/dist/logger.js.map +1 -0
- package/dist/mech-kysely.d.ts +22 -0
- package/dist/mech-kysely.js +88 -0
- package/dist/mech-kysely.js.map +1 -0
- package/dist/mech-sql-client.d.ts +85 -0
- package/dist/mech-sql-client.js +155 -0
- package/dist/mech-sql-client.js.map +1 -0
- package/dist/node.d.ts +4 -0
- package/dist/node.js +10 -0
- package/dist/node.js.map +1 -0
- package/dist/oauth/arctic-providers.d.ts +60 -0
- package/dist/oauth/arctic-providers.js +94 -0
- package/dist/oauth/arctic-providers.js.map +1 -0
- package/dist/oauth/callbacks.d.ts +155 -0
- package/dist/oauth/callbacks.js +286 -0
- package/dist/oauth/callbacks.js.map +1 -0
- package/dist/oauth/github.d.ts +47 -0
- package/dist/oauth/github.js +136 -0
- package/dist/oauth/github.js.map +1 -0
- package/dist/oauth/google.d.ts +49 -0
- package/dist/oauth/google.js +104 -0
- package/dist/oauth/google.js.map +1 -0
- package/dist/oauth/handler.d.ts +31 -0
- package/dist/oauth/handler.js +277 -0
- package/dist/oauth/handler.js.map +1 -0
- package/dist/password-hasher-argon2.d.ts +7 -0
- package/dist/password-hasher-argon2.js +16 -0
- package/dist/password-hasher-argon2.js.map +1 -0
- package/dist/password-hasher.d.ts +12 -0
- package/dist/password-hasher.js +115 -0
- package/dist/password-hasher.js.map +1 -0
- package/dist/react.d.ts +152 -0
- package/dist/react.js +296 -0
- package/dist/react.js.map +1 -0
- package/dist/types.d.ts +190 -0
- package/dist/types.js +7 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/cors.d.ts +65 -0
- package/dist/utils/cors.js +152 -0
- package/dist/utils/cors.js.map +1 -0
- package/dist/utils/normalize-auth-path.d.ts +1 -0
- package/dist/utils/normalize-auth-path.js +8 -0
- package/dist/utils/normalize-auth-path.js.map +1 -0
- package/dist/validation.d.ts +23 -0
- package/dist/validation.js +70 -0
- package/dist/validation.js.map +1 -0
- package/package.json +93 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [0.3.0] - 2025-12-12
|
|
9
|
+
|
|
10
|
+
### 🎉 Major Refactor - Arctic Migration
|
|
11
|
+
|
|
12
|
+
This release completely replaces Better Auth with a lightweight Arctic-based implementation, reducing bundle size from ~150KB to ~15KB while maintaining full feature parity.
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
|
|
16
|
+
- **Arctic OAuth 2.0** - Lightweight OAuth library for GitHub and Google (~10KB)
|
|
17
|
+
- **Argon2id password hashing** - Secure, OWASP-recommended password hashing via @node-rs/argon2
|
|
18
|
+
- **Oslo token generation** - Cryptographically secure token generation with base64url encoding
|
|
19
|
+
- **Custom session management** - Database-backed sessions with configurable expiration
|
|
20
|
+
- **Email/password authentication** - Built-in signup, login, email verification, password reset
|
|
21
|
+
- **React hooks** - Custom `AuthProvider` and `useAuth` hook
|
|
22
|
+
- **Session presets** - Three predefined session configs (default, short, long)
|
|
23
|
+
- **CORS support** - Configurable CORS for browser clients
|
|
24
|
+
- **Password validation** - Configurable minimum length and validation rules
|
|
25
|
+
- **Email enumeration prevention** - Constant-time responses for password reset
|
|
26
|
+
- **Comprehensive test coverage** - 67+ tests for security, validation, token generation
|
|
27
|
+
|
|
28
|
+
### Changed
|
|
29
|
+
|
|
30
|
+
- **BREAKING**: Replaced `better-auth` with `arctic`, `@node-rs/argon2`, `oslo`
|
|
31
|
+
- **BREAKING**: `createClearAuth()` now returns `ClearAuthConfig` instead of Better Auth instance
|
|
32
|
+
- **BREAKING**: Use `handleClearAuthRequest(request, config)` instead of `auth.handler`
|
|
33
|
+
- **BREAKING**: React imports changed from `better-auth/react` to `clearauth/react`
|
|
34
|
+
- **BREAKING**: Session config uses new format with `cookie` object:
|
|
35
|
+
```ts
|
|
36
|
+
// Old (Better Auth)
|
|
37
|
+
session: { updateAge: 86400 }
|
|
38
|
+
|
|
39
|
+
// New (Arctic)
|
|
40
|
+
session: {
|
|
41
|
+
expiresIn: 604800, // 7 days in seconds
|
|
42
|
+
cookie: {
|
|
43
|
+
name: 'session',
|
|
44
|
+
httpOnly: true,
|
|
45
|
+
sameSite: 'lax',
|
|
46
|
+
secure: true,
|
|
47
|
+
path: '/'
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
- **BREAKING**: `baseUrl` parameter now required in `createClearAuth()`
|
|
52
|
+
- Reduced bundle size from ~150KB to ~15KB (90% reduction)
|
|
53
|
+
- Improved TypeScript types with full Kysely integration
|
|
54
|
+
- Enhanced security with Argon2id and PKCE for OAuth
|
|
55
|
+
|
|
56
|
+
### Removed
|
|
57
|
+
|
|
58
|
+
- **BREAKING**: Removed `better-auth` dependency
|
|
59
|
+
- **BREAKING**: Removed all Better Auth plugins and middleware
|
|
60
|
+
- **BREAKING**: Removed `auth.handler` - use `handleClearAuthRequest()` instead
|
|
61
|
+
- **BREAKING**: Removed automatic `process.env` reading (explicit config only)
|
|
62
|
+
|
|
63
|
+
### Migration Guide
|
|
64
|
+
|
|
65
|
+
**Install new dependencies:**
|
|
66
|
+
```bash
|
|
67
|
+
npm uninstall better-auth
|
|
68
|
+
npm install arctic @node-rs/argon2 oslo
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
**Update server code:**
|
|
72
|
+
```ts
|
|
73
|
+
// Before (Better Auth)
|
|
74
|
+
import { createClearAuth } from "clearauth"
|
|
75
|
+
|
|
76
|
+
const auth = createClearAuth({
|
|
77
|
+
emailAndPassword: { enabled: true }
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
export const handler = auth.handler
|
|
81
|
+
|
|
82
|
+
// After (Arctic)
|
|
83
|
+
import { createClearAuth, handleClearAuthRequest } from "clearauth"
|
|
84
|
+
|
|
85
|
+
const config = createClearAuth({
|
|
86
|
+
secret: process.env.AUTH_SECRET!,
|
|
87
|
+
baseUrl: process.env.BASE_URL!,
|
|
88
|
+
database: {
|
|
89
|
+
appId: process.env.MECH_APP_ID!,
|
|
90
|
+
apiKey: process.env.MECH_API_KEY!,
|
|
91
|
+
},
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
export async function handler(request: Request) {
|
|
95
|
+
return handleClearAuthRequest(request, config)
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
**Update React code:**
|
|
100
|
+
```ts
|
|
101
|
+
// Before
|
|
102
|
+
import { useSession, signIn } from "better-auth/react"
|
|
103
|
+
|
|
104
|
+
// After
|
|
105
|
+
import { useAuth } from "clearauth/react"
|
|
106
|
+
|
|
107
|
+
function Component() {
|
|
108
|
+
const { user, signIn } = useAuth()
|
|
109
|
+
// ...
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
**Update session config:**
|
|
114
|
+
```ts
|
|
115
|
+
// Before
|
|
116
|
+
import { createClearAuth } from "clearauth"
|
|
117
|
+
|
|
118
|
+
const auth = createClearAuth({
|
|
119
|
+
session: {
|
|
120
|
+
updateAge: 86400 // 1 day
|
|
121
|
+
}
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
// After
|
|
125
|
+
import { createClearAuth, defaultSessionConfig } from "clearauth"
|
|
126
|
+
|
|
127
|
+
const config = createClearAuth({
|
|
128
|
+
// ...
|
|
129
|
+
session: defaultSessionConfig, // or shortSessionConfig, longSessionConfig
|
|
130
|
+
})
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Security Improvements
|
|
134
|
+
|
|
135
|
+
- Argon2id password hashing (memory-hard, side-channel resistant)
|
|
136
|
+
- PKCE for OAuth (prevents authorization code interception)
|
|
137
|
+
- Email enumeration prevention (constant-time responses)
|
|
138
|
+
- Base64url token encoding (URL-safe, no padding)
|
|
139
|
+
- Improved CSRF protection with state validation
|
|
140
|
+
|
|
141
|
+
## [0.2.0] - 2025-12-11
|
|
142
|
+
|
|
143
|
+
### Added
|
|
144
|
+
|
|
145
|
+
- **Cloudflare Workers compatibility**: Library now works in any JavaScript runtime (Cloudflare Workers, Deno, Bun, etc.)
|
|
146
|
+
- **Cloudflare Pages support**: Full documentation including routing workarounds for Pages Functions
|
|
147
|
+
- Explicit configuration API - all parameters must be passed directly to `createClearAuth()`
|
|
148
|
+
- `isProduction` parameter for runtime environment detection
|
|
149
|
+
- Comprehensive deployment guide comparing Next.js/Vercel, Cloudflare Workers, and Cloudflare Pages
|
|
150
|
+
- Updated integration examples for Next.js (with `toNextJsHandler`), Vite, Cloudflare Workers, and Cloudflare Pages
|
|
151
|
+
- Platform comparison table showing routing differences and best use cases
|
|
152
|
+
|
|
153
|
+
### Installation
|
|
154
|
+
|
|
155
|
+
> **Note:** Install with:
|
|
156
|
+
> ```bash
|
|
157
|
+
> npm install clearauth
|
|
158
|
+
> ```
|
|
159
|
+
|
|
160
|
+
### Changed
|
|
161
|
+
|
|
162
|
+
- **BREAKING**: `secret` parameter is now **required** (was optional, no longer falls back to env vars)
|
|
163
|
+
- **BREAKING**: `database` configuration is now **required** (no longer reads from env vars)
|
|
164
|
+
- **BREAKING**: `createClearAuth()` no longer reads `process.env` automatically
|
|
165
|
+
- **BREAKING**: `MechSqlClient` constructor now requires config object (no env var fallback)
|
|
166
|
+
- **BREAKING**: `createMechKysely()` now requires config parameter (no env var fallback)
|
|
167
|
+
- `createCookieConfig()` now accepts `isProduction` parameter instead of reading `process.env.NODE_ENV`
|
|
168
|
+
- Updated all documentation to reflect explicit configuration requirements
|
|
169
|
+
|
|
170
|
+
### Removed
|
|
171
|
+
|
|
172
|
+
- **BREAKING**: Removed all `process.env` access from library code
|
|
173
|
+
- **BREAKING**: Removed automatic environment variable detection
|
|
174
|
+
- **BREAKING**: Removed env var fallback behavior in all constructors and factory functions
|
|
175
|
+
|
|
176
|
+
### Migration Guide
|
|
177
|
+
|
|
178
|
+
**Before (0.1.0):**
|
|
179
|
+
```ts
|
|
180
|
+
// Library automatically read from process.env
|
|
181
|
+
const auth = createClearAuth({
|
|
182
|
+
emailAndPassword: { enabled: true }
|
|
183
|
+
})
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
**After (0.2.0):**
|
|
187
|
+
```ts
|
|
188
|
+
// Explicit configuration required
|
|
189
|
+
const auth = createClearAuth({
|
|
190
|
+
secret: process.env.BETTER_AUTH_SECRET!,
|
|
191
|
+
database: {
|
|
192
|
+
appId: process.env.MECH_APP_ID!,
|
|
193
|
+
apiKey: process.env.MECH_API_KEY!,
|
|
194
|
+
},
|
|
195
|
+
isProduction: process.env.NODE_ENV === "production",
|
|
196
|
+
emailAndPassword: { enabled: true }
|
|
197
|
+
})
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Documentation
|
|
201
|
+
|
|
202
|
+
- Added comprehensive [Deployment Guide](./DEPLOYMENT_GUIDE.md)
|
|
203
|
+
- Added Cloudflare Workers and Pages examples
|
|
204
|
+
- Updated README with runtime compatibility matrix
|
|
205
|
+
- Added platform-specific routing documentation
|
|
206
|
+
|
|
207
|
+
## [0.1.0] - 2025-11-26
|
|
208
|
+
|
|
209
|
+
### Added
|
|
210
|
+
|
|
211
|
+
- Initial release
|
|
212
|
+
- Better Auth integration with Mech Storage PostgreSQL backend
|
|
213
|
+
- HTTP-based database access via Mech Storage API
|
|
214
|
+
- Kysely query builder with custom Mech dialect
|
|
215
|
+
- React client (`useSession`, `signIn`, `signUp`, `signOut`)
|
|
216
|
+
- Email/password authentication
|
|
217
|
+
- Social login support (GitHub, Google via Better Auth)
|
|
218
|
+
- Next.js App Router support
|
|
219
|
+
- TypeScript support
|
|
220
|
+
- Automatic environment variable configuration
|
|
221
|
+
|
|
222
|
+
### Features
|
|
223
|
+
|
|
224
|
+
- ✅ Better Auth out of the box
|
|
225
|
+
- ✅ Mech Storage PostgreSQL as database backend
|
|
226
|
+
- ✅ Works in Node.js and Cloudflare Workers (with manual config)
|
|
227
|
+
- ✅ React hooks included
|
|
228
|
+
- ✅ TypeScript-first
|
|
229
|
+
|
|
230
|
+
### Documentation
|
|
231
|
+
|
|
232
|
+
- README with quick start guide
|
|
233
|
+
- Integration examples
|
|
234
|
+
- API reference
|
|
235
|
+
- Contributing guidelines
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Dundas
|
|
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.
|
package/README.md
ADDED
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
# ClearAuth
|
|
2
|
+
|
|
3
|
+
A lightweight authentication library built with **Arctic** (OAuth 2.0), pluggable password hashing, and **Mech Storage** as the database backend. Designed for teams who need production-ready auth with minimal bundle size (~15KB vs 150KB).
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Arctic OAuth 2.0** - Lightweight OAuth with GitHub, Google support (~10KB)
|
|
8
|
+
- **Pluggable password hashing** - Argon2id (Node) and PBKDF2 (Edge)
|
|
9
|
+
- **Email/password authentication** - Built-in email verification and password reset
|
|
10
|
+
- **Session management** - Secure, database-backed sessions with configurable expiration
|
|
11
|
+
- **Mech Storage PostgreSQL** as the database (HTTP-based, no direct DB connection needed)
|
|
12
|
+
- **Cloudflare Workers compatible** - Use `clearauth/edge` for OAuth + email/password without native dependencies
|
|
13
|
+
- **React hooks** included (`useAuth`, `AuthProvider`)
|
|
14
|
+
- **TypeScript-first** - Full type safety with Kysely query builder
|
|
15
|
+
- **Minimal bundle size** - ~15KB (vs 150KB for Better Auth)
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
> **Note:** Install from npm as `clearauth`.
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm install clearauth
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Or using a specific version/tag:
|
|
26
|
+
```bash
|
|
27
|
+
npm install clearauth
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Or add to `package.json`:
|
|
31
|
+
```json
|
|
32
|
+
{
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"clearauth": "^0.3.0",
|
|
35
|
+
"arctic": "^2.0.0"
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Entrypoints
|
|
41
|
+
|
|
42
|
+
- **`clearauth`**
|
|
43
|
+
- **Environment:** universal
|
|
44
|
+
- **Default password hasher:** PBKDF2 (WebCrypto)
|
|
45
|
+
- **`clearauth/node`**
|
|
46
|
+
- **Environment:** Node.js
|
|
47
|
+
- **Default password hasher:** Argon2id
|
|
48
|
+
- **API:** `createClearAuthNode(...)`
|
|
49
|
+
- **`clearauth/edge`**
|
|
50
|
+
- **Environment:** Cloudflare Workers / edge runtimes
|
|
51
|
+
- **Default password hasher:** PBKDF2 (no native dependencies)
|
|
52
|
+
- **API:** `createClearAuth(...)`
|
|
53
|
+
- **`clearauth/argon2`**
|
|
54
|
+
- **Environment:** Node.js
|
|
55
|
+
- **Export:** `createArgon2idPasswordHasher(...)` (use to explicitly override)
|
|
56
|
+
|
|
57
|
+
## Migration Notes
|
|
58
|
+
|
|
59
|
+
- **Password hashing default:** `createClearAuth(...)` defaults to PBKDF2 for portability (works in edge runtimes). If you want Argon2id by default in Node.js, use `createClearAuthNode(...)` from `clearauth/node`.
|
|
60
|
+
- **Cookie-based sessions:** `/auth/register` and `/auth/login` set the session cookie on success. `/auth/logout` supports cookie-based logout. If your client previously stored `sessionId` outside cookies, update it to rely on cookies (recommended) or continue sending an explicit `sessionId` in the logout request body.
|
|
61
|
+
|
|
62
|
+
## Quick Start
|
|
63
|
+
|
|
64
|
+
### Server Setup
|
|
65
|
+
|
|
66
|
+
Create `lib/auth.ts`:
|
|
67
|
+
|
|
68
|
+
```ts
|
|
69
|
+
import { createClearAuthNode } from "clearauth/node"
|
|
70
|
+
|
|
71
|
+
export const authConfig = createClearAuthNode({
|
|
72
|
+
secret: process.env.AUTH_SECRET!,
|
|
73
|
+
baseUrl: process.env.BASE_URL || "http://localhost:3000",
|
|
74
|
+
database: {
|
|
75
|
+
appId: process.env.MECH_APP_ID!,
|
|
76
|
+
apiKey: process.env.MECH_API_KEY!,
|
|
77
|
+
},
|
|
78
|
+
oauth: {
|
|
79
|
+
github: {
|
|
80
|
+
clientId: process.env.GITHUB_CLIENT_ID!,
|
|
81
|
+
clientSecret: process.env.GITHUB_CLIENT_SECRET!,
|
|
82
|
+
redirectUri: `${process.env.BASE_URL}/api/auth/callback/github`,
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
})
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Next.js App Router
|
|
89
|
+
|
|
90
|
+
Create `app/api/auth/[...path]/route.ts`:
|
|
91
|
+
|
|
92
|
+
```ts
|
|
93
|
+
import { handleClearAuthRequest } from "clearauth"
|
|
94
|
+
import { authConfig } from "@/lib/auth"
|
|
95
|
+
|
|
96
|
+
export async function GET(request: Request) {
|
|
97
|
+
return handleClearAuthRequest(request, authConfig)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export async function POST(request: Request) {
|
|
101
|
+
return handleClearAuthRequest(request, authConfig)
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Cloudflare Workers
|
|
106
|
+
|
|
107
|
+
Create `src/auth.ts`:
|
|
108
|
+
|
|
109
|
+
```ts
|
|
110
|
+
import { createClearAuth, handleClearAuthEdgeRequest } from "clearauth/edge"
|
|
111
|
+
|
|
112
|
+
export function createAuth(env: Env) {
|
|
113
|
+
return createClearAuth({
|
|
114
|
+
secret: env.AUTH_SECRET,
|
|
115
|
+
baseUrl: "https://your-worker.workers.dev",
|
|
116
|
+
database: {
|
|
117
|
+
appId: env.MECH_APP_ID,
|
|
118
|
+
apiKey: env.MECH_API_KEY,
|
|
119
|
+
},
|
|
120
|
+
isProduction: true,
|
|
121
|
+
})
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export default {
|
|
125
|
+
async fetch(request: Request, env: Env): Promise<Response> {
|
|
126
|
+
const url = new URL(request.url)
|
|
127
|
+
|
|
128
|
+
if (url.pathname.startsWith("/auth")) {
|
|
129
|
+
const config = createAuth(env)
|
|
130
|
+
return handleClearAuthEdgeRequest(request, config)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return new Response("Hello World")
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### React Client
|
|
139
|
+
|
|
140
|
+
Wrap your app with `AuthProvider`:
|
|
141
|
+
|
|
142
|
+
```tsx
|
|
143
|
+
// app/providers.tsx
|
|
144
|
+
"use client"
|
|
145
|
+
|
|
146
|
+
import { AuthProvider } from "clearauth/react"
|
|
147
|
+
|
|
148
|
+
export function Providers({ children }: { children: React.ReactNode }) {
|
|
149
|
+
return (
|
|
150
|
+
<AuthProvider baseUrl="/api/auth">
|
|
151
|
+
{children}
|
|
152
|
+
</AuthProvider>
|
|
153
|
+
)
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Use in components:
|
|
158
|
+
|
|
159
|
+
```tsx
|
|
160
|
+
"use client"
|
|
161
|
+
|
|
162
|
+
import { useAuth } from "clearauth/react"
|
|
163
|
+
|
|
164
|
+
export function LoginButton() {
|
|
165
|
+
const { user, loading, signIn, signOut } = useAuth()
|
|
166
|
+
|
|
167
|
+
if (loading) return <p>Loading...</p>
|
|
168
|
+
|
|
169
|
+
if (user) {
|
|
170
|
+
return (
|
|
171
|
+
<div>
|
|
172
|
+
<p>Welcome, {user.email}!</p>
|
|
173
|
+
<button onClick={signOut}>Sign Out</button>
|
|
174
|
+
</div>
|
|
175
|
+
)
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
return (
|
|
179
|
+
<button onClick={() => signIn("user@example.com", "password")}>
|
|
180
|
+
Sign In
|
|
181
|
+
</button>
|
|
182
|
+
)
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
## Configuration
|
|
187
|
+
|
|
188
|
+
### Required Configuration
|
|
189
|
+
|
|
190
|
+
All configuration must be passed explicitly to `createClearAuth()`:
|
|
191
|
+
|
|
192
|
+
| Parameter | Type | Required | Description |
|
|
193
|
+
|-----------|------|----------|-------------|
|
|
194
|
+
| `secret` | `string` | Yes | Secret for signing tokens (minimum 32 characters recommended) |
|
|
195
|
+
| `baseUrl` | `string` | Yes | Your application's base URL (e.g., `https://example.com`) |
|
|
196
|
+
| `database.appId` | `string` | Yes | Your Mech app UUID |
|
|
197
|
+
| `database.apiKey` | `string` | Yes | Your Mech API key |
|
|
198
|
+
| `isProduction` | `boolean` | No | Set to `true` in production (enables secure cookies) |
|
|
199
|
+
|
|
200
|
+
### Optional Configuration
|
|
201
|
+
|
|
202
|
+
| Parameter | Type | Description |
|
|
203
|
+
|-----------|------|-------------|
|
|
204
|
+
| `oauth` | `OAuthProvidersConfig` | OAuth provider configuration (GitHub, Google) |
|
|
205
|
+
| `session` | `SessionConfig` | Session configuration (expiration, cookie settings) |
|
|
206
|
+
| `password` | `PasswordConfig` | Password validation rules (minLength) |
|
|
207
|
+
| `cors` | `CorsConfig` | CORS configuration for browser clients |
|
|
208
|
+
|
|
209
|
+
### Session Presets
|
|
210
|
+
|
|
211
|
+
Three session configurations are available:
|
|
212
|
+
|
|
213
|
+
```ts
|
|
214
|
+
import {
|
|
215
|
+
defaultSessionConfig, // 7 days, sameSite: lax
|
|
216
|
+
shortSessionConfig, // 1 hour, sameSite: strict
|
|
217
|
+
longSessionConfig // 30 days, sameSite: lax
|
|
218
|
+
} from "clearauth"
|
|
219
|
+
|
|
220
|
+
const config = createClearAuth({
|
|
221
|
+
// ...
|
|
222
|
+
session: shortSessionConfig, // Use preset
|
|
223
|
+
})
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
### Environment Variables (Recommended Pattern)
|
|
227
|
+
|
|
228
|
+
**Node.js / Next.js (.env.local):**
|
|
229
|
+
```bash
|
|
230
|
+
AUTH_SECRET=your-secret-key-at-least-32-chars
|
|
231
|
+
BASE_URL=http://localhost:3000
|
|
232
|
+
MECH_APP_ID=550e8400-e29b-41d4-a716-446655440000
|
|
233
|
+
MECH_API_KEY=your-mech-api-key
|
|
234
|
+
|
|
235
|
+
# OAuth (optional)
|
|
236
|
+
GITHUB_CLIENT_ID=your-github-client-id
|
|
237
|
+
GITHUB_CLIENT_SECRET=your-github-client-secret
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
**Cloudflare Workers (wrangler.toml):**
|
|
241
|
+
```toml
|
|
242
|
+
[vars]
|
|
243
|
+
BASE_URL = "https://your-worker.workers.dev"
|
|
244
|
+
|
|
245
|
+
# Use `wrangler secret put` for sensitive values:
|
|
246
|
+
# wrangler secret put AUTH_SECRET
|
|
247
|
+
# wrangler secret put MECH_API_KEY
|
|
248
|
+
# wrangler secret put GITHUB_CLIENT_SECRET
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
## API Reference
|
|
252
|
+
|
|
253
|
+
### `createClearAuth(options)`
|
|
254
|
+
|
|
255
|
+
Creates an authentication configuration object.
|
|
256
|
+
|
|
257
|
+
```ts
|
|
258
|
+
import { createClearAuth } from "clearauth"
|
|
259
|
+
|
|
260
|
+
const config = createClearAuth({
|
|
261
|
+
secret: process.env.AUTH_SECRET!,
|
|
262
|
+
baseUrl: "https://example.com",
|
|
263
|
+
database: {
|
|
264
|
+
appId: process.env.MECH_APP_ID!,
|
|
265
|
+
apiKey: process.env.MECH_API_KEY!,
|
|
266
|
+
},
|
|
267
|
+
oauth: {
|
|
268
|
+
github: {
|
|
269
|
+
clientId: process.env.GITHUB_CLIENT_ID!,
|
|
270
|
+
clientSecret: process.env.GITHUB_CLIENT_SECRET!,
|
|
271
|
+
redirectUri: "https://example.com/auth/callback/github",
|
|
272
|
+
},
|
|
273
|
+
},
|
|
274
|
+
session: defaultSessionConfig,
|
|
275
|
+
password: { minLength: 12 },
|
|
276
|
+
})
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
**Returns:** `ClearAuthConfig` - Configuration object to pass to `handleClearAuthRequest()`
|
|
280
|
+
|
|
281
|
+
### `handleClearAuthRequest(request, config)`
|
|
282
|
+
|
|
283
|
+
Universal request handler for all authentication routes.
|
|
284
|
+
|
|
285
|
+
```ts
|
|
286
|
+
import { handleClearAuthRequest } from "clearauth"
|
|
287
|
+
|
|
288
|
+
const response = await handleClearAuthRequest(request, authConfig)
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
**Parameters:**
|
|
292
|
+
- `request: Request` - Web standard Request object
|
|
293
|
+
- `config: ClearAuthConfig` - Configuration from `createClearAuth()`
|
|
294
|
+
|
|
295
|
+
**Returns:** `Promise<Response>` - Web standard Response object
|
|
296
|
+
|
|
297
|
+
### React Hooks
|
|
298
|
+
|
|
299
|
+
#### `<AuthProvider>`
|
|
300
|
+
|
|
301
|
+
Wraps your app to provide authentication context.
|
|
302
|
+
|
|
303
|
+
```tsx
|
|
304
|
+
import { AuthProvider } from "clearauth/react"
|
|
305
|
+
|
|
306
|
+
<AuthProvider baseUrl="/api/auth">
|
|
307
|
+
{children}
|
|
308
|
+
</AuthProvider>
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
#### `useAuth()`
|
|
312
|
+
|
|
313
|
+
Access authentication state and actions.
|
|
314
|
+
|
|
315
|
+
```tsx
|
|
316
|
+
import { useAuth } from "clearauth/react"
|
|
317
|
+
|
|
318
|
+
const {
|
|
319
|
+
user, // Current user or null
|
|
320
|
+
loading, // Loading state
|
|
321
|
+
error, // Error message or null
|
|
322
|
+
signIn, // (email, password) => Promise<void>
|
|
323
|
+
signUp, // (email, password, name?) => Promise<void>
|
|
324
|
+
signOut, // () => Promise<void>
|
|
325
|
+
loginWithGithub, // () => Promise<void>
|
|
326
|
+
loginWithGoogle, // () => Promise<void>
|
|
327
|
+
refresh, // () => Promise<void>
|
|
328
|
+
} = useAuth()
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
## Authentication Routes
|
|
332
|
+
|
|
333
|
+
All routes are handled by `handleClearAuthRequest()`:
|
|
334
|
+
|
|
335
|
+
| Route | Method | Description |
|
|
336
|
+
|-------|--------|-------------|
|
|
337
|
+
| `/auth/register` | POST | Email/password registration |
|
|
338
|
+
| `/auth/login` | POST | Email/password login |
|
|
339
|
+
| `/auth/logout` | POST | Sign out current user |
|
|
340
|
+
| `/auth/session` | GET | Get current session |
|
|
341
|
+
| `/auth/verify-email` | POST | Verify email with token |
|
|
342
|
+
| `/auth/resend-verification` | POST | Resend verification email |
|
|
343
|
+
| `/auth/request-reset` | POST | Request password reset |
|
|
344
|
+
| `/auth/reset-password` | POST | Reset password with token |
|
|
345
|
+
| `/auth/oauth/github` | GET | Initiate GitHub OAuth flow |
|
|
346
|
+
| `/auth/callback/github` | GET | GitHub OAuth callback |
|
|
347
|
+
| `/auth/oauth/google` | GET | Initiate Google OAuth flow |
|
|
348
|
+
| `/auth/callback/google` | GET | Google OAuth callback |
|
|
349
|
+
|
|
350
|
+
## How It Works
|
|
351
|
+
|
|
352
|
+
1. **Arctic** handles OAuth 2.0 flows (GitHub, Google) with PKCE and state validation
|
|
353
|
+
2. **Argon2id** hashes passwords securely (memory-hard, side-channel resistant)
|
|
354
|
+
3. **Oslo** generates cryptographically secure tokens (base64url encoded)
|
|
355
|
+
4. **Kysely** provides type-safe SQL queries to Mech Storage
|
|
356
|
+
5. **Mech Storage** stores users, sessions, and OAuth accounts via HTTP API
|
|
357
|
+
|
|
358
|
+
This architecture means:
|
|
359
|
+
- No heavyweight auth frameworks required
|
|
360
|
+
- Works in any JavaScript runtime (Node.js, Cloudflare Workers, Deno, Bun)
|
|
361
|
+
- No direct database connections needed
|
|
362
|
+
- Minimal bundle size (~15KB vs 150KB)
|
|
363
|
+
- Full TypeScript type safety
|
|
364
|
+
|
|
365
|
+
## Security Features
|
|
366
|
+
|
|
367
|
+
- ✅ **Argon2id password hashing** - OWASP recommended, memory-hard algorithm
|
|
368
|
+
- ✅ **Email enumeration prevention** - Constant-time responses for password reset
|
|
369
|
+
- ✅ **CSRF protection** - State parameter validation in OAuth flows
|
|
370
|
+
- ✅ **PKCE for OAuth** - Prevents authorization code interception
|
|
371
|
+
- ✅ **Secure session cookies** - httpOnly, sameSite, secure flags
|
|
372
|
+
- ✅ **Token expiration** - Configurable session and token TTLs
|
|
373
|
+
- ✅ **Timing attack resistance** - Constant-time comparisons
|
|
374
|
+
|
|
375
|
+
## Cloudflare Compatibility
|
|
376
|
+
|
|
377
|
+
Compatible with Cloudflare Workers and Pages when using an HTTP-based database backend. Note that email/password uses `@node-rs/argon2` (native) and may require a Node runtime.
|
|
378
|
+
|
|
379
|
+
- ✅ **No `process.env` usage** - All configuration is explicit
|
|
380
|
+
- ✅ **Works with Workers `env` bindings** - Pass secrets from environment
|
|
381
|
+
- ✅ **HTTP-based database** - No TCP connections required
|
|
382
|
+
- ✅ **Edge-friendly** - No Node.js-specific APIs
|
|
383
|
+
- ✅ **Web Standards** - Uses Request/Response objects
|
|
384
|
+
|
|
385
|
+
## Development
|
|
386
|
+
|
|
387
|
+
```bash
|
|
388
|
+
# Install dependencies
|
|
389
|
+
bun install
|
|
390
|
+
|
|
391
|
+
# Run tests
|
|
392
|
+
bun run test
|
|
393
|
+
|
|
394
|
+
# Run tests in watch mode
|
|
395
|
+
bun run test:watch
|
|
396
|
+
|
|
397
|
+
# Build
|
|
398
|
+
bun run build
|
|
399
|
+
|
|
400
|
+
# Output appears in dist/
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
## Migration from Better Auth
|
|
404
|
+
|
|
405
|
+
If migrating from Better Auth:
|
|
406
|
+
|
|
407
|
+
1. Replace `better-auth` dependency with `arctic`, `@node-rs/argon2`, `oslo`
|
|
408
|
+
2. Update `createClearAuth()` - returns `ClearAuthConfig` instead of auth instance
|
|
409
|
+
3. Use `handleClearAuthRequest()` instead of `auth.handler`
|
|
410
|
+
4. Update React imports from `better-auth/react` to `clearauth/react`
|
|
411
|
+
5. Update session config - uses new format with `cookie` object
|
|
412
|
+
|
|
413
|
+
See [MIGRATION_GUIDE.md](./MIGRATION_GUIDE.md) for detailed migration steps.
|
|
414
|
+
|
|
415
|
+
## License
|
|
416
|
+
|
|
417
|
+
MIT
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Email/Password Authentication HTTP Handler
|
|
3
|
+
*
|
|
4
|
+
* Handles HTTP requests for email/password authentication:
|
|
5
|
+
* - POST /auth/register - User registration
|
|
6
|
+
* - POST /auth/verify-email - Email verification
|
|
7
|
+
* - POST /auth/login - User login
|
|
8
|
+
* - POST /auth/logout - Session deletion
|
|
9
|
+
* - POST /auth/request-reset - Request password reset
|
|
10
|
+
* - POST /auth/reset-password - Reset password with token
|
|
11
|
+
*/
|
|
12
|
+
import type { ClearAuthConfig } from '../types.js';
|
|
13
|
+
/**
|
|
14
|
+
* Main authentication request handler
|
|
15
|
+
*
|
|
16
|
+
* Routes incoming requests to the appropriate handler based on the URL path.
|
|
17
|
+
*
|
|
18
|
+
* Supported routes:
|
|
19
|
+
* - GET /auth/session - Get current user session
|
|
20
|
+
* - POST /auth/register - Register new user
|
|
21
|
+
* - POST /auth/verify-email - Verify email with token
|
|
22
|
+
* - POST /auth/resend-verification - Resend verification email
|
|
23
|
+
* - POST /auth/login - Login with email/password
|
|
24
|
+
* - POST /auth/logout - Logout user
|
|
25
|
+
* - POST /auth/request-reset - Request password reset
|
|
26
|
+
* - POST /auth/reset-password - Reset password with token
|
|
27
|
+
*
|
|
28
|
+
* @param request - HTTP request
|
|
29
|
+
* @param config - Clear Auth configuration
|
|
30
|
+
* @returns HTTP response
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```ts
|
|
34
|
+
* const response = await handleAuthRequest(request, config)
|
|
35
|
+
* return response
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export declare function handleAuthRequest(request: Request, config: ClearAuthConfig): Promise<Response>;
|