@rudderjs/auth 5.0.0 → 5.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/README.md CHANGED
@@ -15,31 +15,13 @@ pnpm add @rudderjs/auth @rudderjs/hash @rudderjs/session
15
15
  import { User } from '../app/Models/User.js'
16
16
 
17
17
  export default {
18
- defaults: {
19
- guard: 'web',
20
- },
21
- guards: {
22
- web: { driver: 'session', provider: 'users' },
23
- },
24
- providers: {
25
- users: { driver: 'eloquent', model: User },
26
- },
18
+ defaults: { guard: 'web' },
19
+ guards: { web: { driver: 'session', provider: 'users' } },
20
+ providers:{ users: { driver: 'eloquent', model: User } },
27
21
  }
28
-
29
- // bootstrap/providers.ts
30
- import { SessionProvider } from '@rudderjs/session'
31
- import { HashProvider } from '@rudderjs/hash'
32
- import { AuthProvider } from '@rudderjs/auth'
33
-
34
- export default [
35
- SessionProvider,
36
- HashProvider,
37
- AuthProvider,
38
- ]
39
22
  ```
40
23
 
41
- > `AuthProvider` is the service-provider class list it directly in the providers array.
42
- > `auth()` (lowercase) is the per-request helper — see below.
24
+ `AuthProvider`, `SessionProvider`, and `HashProvider` are picked up by [auto-discovery](https://github.com/rudderjs/rudder/blob/main/docs/guide/service-providers.md#auto-discovery)`pnpm rudder providers:discover` (or `--install` during scaffold) is all that's needed.
43
25
 
44
26
  ## Usage
45
27
 
@@ -70,6 +52,27 @@ Route.get('/profile', async (req) => {
70
52
  matched by `withRouting({ web })` has the auth context populated before your
71
53
  handler runs.
72
54
 
55
+ ### Reading the user from a view
56
+
57
+ When `@rudderjs/vite` is installed, `AuthProvider.boot()` also registers a
58
+ page-context enhancer that exposes the current user on `pageContext.user` —
59
+ controller views (and any Vike page) can read it directly without a
60
+ `+data.ts` or controller plumbing:
61
+
62
+ ```tsx
63
+ // app/Views/Dashboard.tsx
64
+ import { usePageContext } from 'vike-react/usePageContext'
65
+
66
+ export default function Dashboard() {
67
+ const { user } = usePageContext() // typed via Vike.PageContext augmentation
68
+ return <h1>Hello {user?.name ?? 'guest'}</h1>
69
+ }
70
+ ```
71
+
72
+ `pageContext.user` is `null` for guests. The registration is lazy and silently
73
+ no-ops when `@rudderjs/vite` isn't installed, so the package stays usable
74
+ standalone.
75
+
73
76
  **API routes stay stateless.** `AuthMiddleware` does not run on the `api` group
74
77
  by default — `req.user` will be `undefined`, and `Auth.user()` returns `null`.
75
78
  For token-based API auth, reach for [`@rudderjs/passport`](../passport):
@@ -1,273 +1,40 @@
1
1
  ---
2
2
  name: auth-setup
3
3
  description: Setting up authentication with guards, sessions, registration, password reset, gates/policies, and vendor views in RudderJS
4
+ license: MIT
5
+ appliesTo:
6
+ - '@rudderjs/auth'
7
+ trigger: configuring guards/providers in `config/auth.ts`, vendoring auth views, wiring `Gate`/`Policy`, or working with password reset / email verification
8
+ skip: a route handler that just reads `Auth.user()` — no setup needed
9
+ metadata:
10
+ author: rudderjs
4
11
  ---
5
12
 
6
13
  # Auth Setup
7
14
 
8
15
  ## When to use this skill
9
16
 
10
- Load this skill when you need to set up authentication, configure guards, add login/register views, implement authorization gates/policies, or work with password reset and email verification.
17
+ Load when you're configuring guards/providers, vendoring auth views, wiring `Gate`/`Policy` authorization, or working with password reset / email verification. For depth, open the rule file matching your task.
11
18
 
12
- ## Key concepts
19
+ ## Quick Reference
13
20
 
14
- - **AuthManager**: Process-wide DI singleton that creates fresh `SessionGuard` instances per call (never cached -- prevents ghost user leaks across requests).
15
- - **Guard contract**: `user()`, `check()`, `guest()`, `attempt()`, `login()`, `logout()` -- all async.
16
- - **`auth()` helper**: Returns the current request's `AuthManager` via AsyncLocalStorage. Mirrors Laravel's `auth()->user()`.
17
- - **Auth facade**: `Auth.user()`, `Auth.check()` etc. -- static class that proxies to `currentAuth()`.
18
- - **AuthMiddleware**: Sets up the auth ALS context and populates `req.user` for every request.
19
- - **RequireAuth**: Returns 401 if not authenticated.
20
- - **RequireGuest**: Redirects authenticated users away from guest-only pages (login, register).
21
- - **Gate/Policy**: Authorization system for checking abilities and model-level policies.
21
+ | Task | Open |
22
+ |---|---|
23
+ | Provider setup install deps, `config/auth.ts`, register provider, make User authenticatable | `rules/provider-setup.md` |
24
+ | Reading the current user — `auth()`, `Auth` facade, `RequireAuth` / `RequireGuest` middleware, login/logout endpoints | `rules/guards-and-handlers.md` |
25
+ | Login / register UI — `vendor:publish` auth views, `registerAuthRoutes`, custom paths and view ids | `rules/auth-views.md` |
26
+ | Authorization `Gate.define`, model `Policy` classes, `before` callbacks | `rules/gates-and-policies.md` |
27
+ | Email verification + password reset `MustVerifyEmail`, `verificationUrl`, `PasswordBroker` | `rules/email-and-password-reset.md` |
22
28
 
23
- ## Step-by-step
29
+ ## Key concepts (load once)
24
30
 
25
- ### 1. Install dependencies
26
-
27
- Auth requires `@rudderjs/session` and `@rudderjs/hash` as peer dependencies:
28
-
29
- ```bash
30
- pnpm add @rudderjs/auth @rudderjs/session @rudderjs/hash
31
- ```
32
-
33
- ### 2. Configure auth (config/auth.ts)
34
-
35
- ```ts
36
- import { User } from '../app/Models/User.js'
37
- import type { AuthConfig } from '@rudderjs/auth'
38
-
39
- export default {
40
- defaults: {
41
- guard: 'web',
42
- },
43
- guards: {
44
- web: {
45
- driver: 'session',
46
- provider: 'users',
47
- },
48
- },
49
- providers: {
50
- users: {
51
- driver: 'eloquent',
52
- model: User,
53
- },
54
- },
55
- } satisfies AuthConfig
56
- ```
57
-
58
- ### 3. Register the provider (bootstrap/providers.ts)
59
-
60
- ```ts
61
- import { defaultProviders } from '@rudderjs/core'
62
- // AuthProvider is auto-discovered via defaultProviders() if @rudderjs/auth is installed.
63
- // It requires HashProvider and SessionProvider to boot before it.
64
- export default [
65
- ...(await defaultProviders()),
66
- // ... your app providers
67
- ]
68
- ```
69
-
70
- ### 4. Make the User model authenticatable
71
-
72
- ```ts
73
- import { Model, Hidden } from '@rudderjs/orm'
74
- import type { Authenticatable } from '@rudderjs/auth'
75
-
76
- export class User extends Model implements Authenticatable {
77
- static fillable = ['name', 'email', 'password']
78
-
79
- @Hidden password = ''
80
-
81
- getAuthIdentifier(): string { return String(this.id) }
82
- getAuthPassword(): string { return this.password }
83
- getRememberToken(): string | null { return null }
84
- setRememberToken(_token: string): void {}
85
- }
86
- ```
87
-
88
- ### 5. Use auth in route handlers
89
-
90
- ```ts
91
- import { auth, Auth, RequireAuth } from '@rudderjs/auth'
92
-
93
- // Using the auth() helper (Laravel-style)
94
- router.get('/api/me', async (req, res) => {
95
- const user = await auth().user()
96
- if (!user) return res.status(401).json({ message: 'Unauthorized' })
97
- res.json({ user })
98
- })
99
-
100
- // Using the Auth facade
101
- router.get('/api/profile', async (req, res) => {
102
- if (await Auth.guest()) return res.status(401).json({ message: 'Unauthorized' })
103
- const user = await Auth.user()
104
- res.json({ user })
105
- })
106
-
107
- // Using RequireAuth middleware
108
- router.get('/api/dashboard', RequireAuth(), async (req, res) => {
109
- // req.user is guaranteed to exist here
110
- res.json({ user: req.user })
111
- })
112
- ```
113
-
114
- ### 6. Login / logout endpoints
115
-
116
- ```ts
117
- router.post('/auth/login', async (req, res) => {
118
- const { email, password } = req.body
119
- const success = await auth().attempt({ email, password })
120
- if (!success) {
121
- return res.status(422).json({ message: 'Invalid credentials.' })
122
- }
123
- const user = await auth().user()
124
- res.json({ user })
125
- })
126
-
127
- router.post('/auth/register', async (req, res) => {
128
- const user = await User.create({
129
- name: req.body.name,
130
- email: req.body.email,
131
- password: req.body.password, // hashed by Attribute mutator
132
- })
133
- await auth().login(user)
134
- res.json({ user })
135
- })
136
-
137
- router.post('/auth/logout', RequireAuth(), async (req, res) => {
138
- await auth().logout()
139
- res.json({ message: 'Logged out.' })
140
- })
141
- ```
142
-
143
- ### 7. Set up auth views (login/register pages)
144
-
145
- Vendor the view files into your app:
146
-
147
- ```bash
148
- pnpm rudder vendor:publish --tag=auth-views
149
- ```
150
-
151
- This copies `@rudderjs/auth/views/react/` into `app/Views/Auth/`. Then register routes:
152
-
153
- ```ts
154
- // routes/web.ts
155
- import { Route } from '@rudderjs/router'
156
- import { registerAuthRoutes } from '@rudderjs/auth/routes'
157
-
158
- registerAuthRoutes(Route)
159
- // Registers: GET /login, GET /register, GET /forgot-password, GET /reset-password
160
- ```
161
-
162
- Customize paths and view ids:
163
-
164
- ```ts
165
- registerAuthRoutes(Route, {
166
- paths: {
167
- login: '/sign-in',
168
- register: '/sign-up',
169
- },
170
- views: {
171
- login: 'auth.sign-in', // maps to app/Views/Auth/SignIn.tsx
172
- register: 'auth.sign-up',
173
- },
174
- homeUrl: '/dashboard', // redirect destination for authenticated users
175
- })
176
- ```
177
-
178
- ### 8. Authorization with Gates
179
-
180
- ```ts
181
- import { Gate, Policy, AuthorizationError } from '@rudderjs/auth'
182
-
183
- // Define abilities
184
- Gate.define('manage-settings', (user) => user.role === 'admin')
185
- Gate.define('edit-post', (user, post) => post.authorId === user.getAuthIdentifier())
186
-
187
- // Check in handlers
188
- if (await Gate.allows('manage-settings')) { /* ... */ }
189
- if (await Gate.denies('edit-post', post)) { /* ... */ }
190
-
191
- // Throw 403 if denied
192
- await Gate.authorize('edit-post', post)
193
-
194
- // Before callback -- runs before all checks
195
- Gate.before((user, ability) => {
196
- if (user.role === 'super-admin') return true // allow everything
197
- return null // fall through to normal checks
198
- })
199
- ```
200
-
201
- ### 9. Model policies
202
-
203
- ```ts
204
- import { Policy } from '@rudderjs/auth'
205
- import type { Authenticatable } from '@rudderjs/auth'
206
-
207
- class PostPolicy extends Policy {
208
- before(user: Authenticatable) {
209
- if ((user as any).role === 'admin') return true
210
- return null // fall through
211
- }
212
-
213
- view(user: Authenticatable, post: Post) {
214
- return post.isPublished || post.authorId === user.getAuthIdentifier()
215
- }
216
-
217
- update(user: Authenticatable, post: Post) {
218
- return post.authorId === user.getAuthIdentifier()
219
- }
220
-
221
- delete(user: Authenticatable, post: Post) {
222
- return post.authorId === user.getAuthIdentifier()
223
- }
224
- }
225
-
226
- // Register the policy
227
- Gate.policy(Post, PostPolicy)
228
-
229
- // Use it
230
- await Gate.authorize('update', post) // auto-finds PostPolicy.update()
231
- ```
232
-
233
- ### 10. Email verification
234
-
235
- ```ts
236
- import { EnsureEmailIsVerified, verificationUrl, handleEmailVerification } from '@rudderjs/auth'
237
- import type { MustVerifyEmail } from '@rudderjs/auth'
238
-
239
- // Make user implement MustVerifyEmail
240
- class User extends Model implements Authenticatable, MustVerifyEmail {
241
- hasVerifiedEmail() { return this.emailVerifiedAt !== null }
242
- async markEmailAsVerified() { await User.update(this.id, { emailVerifiedAt: new Date() }) }
243
- getEmailForVerification() { return this.email }
244
- }
245
-
246
- // Protect routes
247
- router.get('/dashboard', RequireAuth(), EnsureEmailIsVerified(), handler)
248
-
249
- // Generate verification URL (for sending in emails)
250
- const url = verificationUrl(user)
251
- ```
252
-
253
- ### 11. Password reset
254
-
255
- ```ts
256
- import { PasswordBroker, MemoryTokenRepository } from '@rudderjs/auth'
257
-
258
- const broker = new PasswordBroker(new MemoryTokenRepository())
259
- // In production, implement TokenRepository backed by your database
260
- ```
31
+ - **AuthManager** — process-wide DI singleton that creates fresh `SessionGuard` instances per call. **Never cached** — cached guards leak `_user` across requests.
32
+ - **`auth()` helper** — Laravel-style accessor returning the request-scoped `AuthManager` via AsyncLocalStorage.
33
+ - **`Auth` facade** `Auth.user()`, `Auth.check()`, etc. static class that proxies to `currentAuth()`.
34
+ - **Middleware groups** — `AuthMiddleware` auto-installs on the `web` group only. API routes are stateless by default; use `RequireBearer()` + `scope(...)` (passport) for token auth per-route.
35
+ - **`SessionGuard.user()` soft-fails** — returns `null` (not throw) when there's no ALS context, matching Laravel's `Auth::user()` semantics.
36
+ - **Peer deps**: `@rudderjs/session` and `@rudderjs/hash` are **required peers**. `HashProvider` must boot before `AuthProvider` (`defaultProviders()` orders this automatically).
261
37
 
262
38
  ## Examples
263
39
 
264
- See `playground/config/auth.ts` for configuration, `playground/app/Models/User.ts` for the model, `playground/routes/web.ts` for route registration, and `playground/app/Views/Auth/` for vendored view files.
265
-
266
- ## Common pitfalls
267
-
268
- - **Ghost signed-in user**: `AuthManager` must NOT cache `SessionGuard` instances. The manager is a DI singleton; cached guards leak `_user` across requests.
269
- - **Provider boot order**: `HashProvider` and `SessionProvider` must boot before `AuthProvider`. With `defaultProviders()`, this is handled automatically.
270
- - **Session middleware required**: Auth views require session middleware. Ensure `@rudderjs/session` is installed and its provider is registered.
271
- - **View route override**: Auth view files need `export const route = '/login'` etc. so SPA navigation works correctly (URL must match Vike's route table).
272
- - **POST handlers not included**: `registerAuthRoutes()` only registers GET routes for the UI pages. POST endpoints for login/register/logout are your responsibility in `routes/api.ts`.
273
- - **Guard driver**: Currently only `'session'` is supported as a guard driver. API token guards are planned.
40
+ See `playground/config/auth.ts`, `playground/app/Models/User.ts`, `playground/routes/web.ts`, and `playground/app/Views/Auth/`.
@@ -0,0 +1,90 @@
1
+ # Auth Views (Login / Register UI)
2
+
3
+ ## Vendor the view files
4
+
5
+ `@rudderjs/auth` ships React and Vue auth views. Vendor them into your app:
6
+
7
+ ```bash
8
+ pnpm rudder vendor:publish --tag=auth-views
9
+ ```
10
+
11
+ This copies `@rudderjs/auth/views/react/` (or `/vue/`) into `app/Views/Auth/`. After vendoring, the files belong to your app — edit them freely.
12
+
13
+ ## Register the controller routes
14
+
15
+ ```ts
16
+ // routes/web.ts
17
+ import { Route } from '@rudderjs/router'
18
+ import { registerAuthRoutes } from '@rudderjs/auth/routes'
19
+
20
+ registerAuthRoutes(Route)
21
+ ```
22
+
23
+ `registerAuthRoutes(Route)` registers:
24
+
25
+ | URL | View id |
26
+ |---|---|
27
+ | `GET /login` | `auth.login` |
28
+ | `GET /register` | `auth.register` |
29
+ | `GET /forgot-password` | `auth.forgot-password` |
30
+ | `GET /reset-password` | `auth.reset-password` |
31
+
32
+ The view-id mapping uses `view('id', props)` and lands in `app/Views/Auth/<File>.tsx`.
33
+
34
+ ## Customize paths and view ids
35
+
36
+ ```ts
37
+ registerAuthRoutes(Route, {
38
+ paths: {
39
+ login: '/sign-in',
40
+ register: '/sign-up',
41
+ },
42
+ views: {
43
+ login: 'auth.sign-in', // maps to app/Views/Auth/SignIn.tsx
44
+ register: 'auth.sign-up',
45
+ },
46
+ homeUrl: '/dashboard', // redirect destination for authenticated users
47
+ })
48
+ ```
49
+
50
+ ## Add the `route` export to vendored views
51
+
52
+ Vendored auth views need an explicit URL because the id-derived default (`/auth/login`) doesn't match the controller route (`/login`).
53
+
54
+ ```tsx
55
+ // app/Views/Auth/Login.tsx
56
+ export const route = '/login'
57
+
58
+ export default function Login(props: { /* ... */ }) { /* ... */ }
59
+ ```
60
+
61
+ Without this, **SPA navigation falls back to full page reloads** because Vike's client route table doesn't match the browser URL.
62
+
63
+ ## Pitfalls
64
+
65
+ ❌ **Don't** assume POST handlers come from `registerAuthRoutes`:
66
+
67
+ ```ts
68
+ registerAuthRoutes(Route)
69
+ // ❌ POST /login / POST /register / POST /logout — those are YOUR job
70
+ ```
71
+
72
+ ✅ **Do** add them in `routes/api.ts` or `routes/web.ts` using `auth().attempt()` / `auth().login()` / `auth().logout()`.
73
+
74
+ ❌ **Don't** skip the `route` export when customizing URLs:
75
+
76
+ ```tsx
77
+ // app/Views/Auth/Login.tsx — no route export
78
+ export default function Login() { /* ... */ }
79
+ ```
80
+
81
+ ✅ **Do** add it so SPA nav works:
82
+
83
+ ```tsx
84
+ export const route = '/sign-in'
85
+ export default function Login() { /* ... */ }
86
+ ```
87
+
88
+ ❌ **Don't** mix `vike-react` and `vike-vue` — the scanner errors at boot.
89
+
90
+ ✅ **Do** pick one renderer per project; vendor the matching auth views (`--tag=auth-views` auto-detects).
@@ -0,0 +1,91 @@
1
+ # Email Verification + Password Reset
2
+
3
+ ## Email verification
4
+
5
+ Implement `MustVerifyEmail` on your User model:
6
+
7
+ ```ts
8
+ import type { Authenticatable, MustVerifyEmail } from '@rudderjs/auth'
9
+
10
+ class User extends Model implements Authenticatable, MustVerifyEmail {
11
+ hasVerifiedEmail() { return this.emailVerifiedAt !== null }
12
+ getEmailForVerification() { return this.email }
13
+ async markEmailAsVerified() {
14
+ await User.update(this.id, { emailVerifiedAt: new Date() })
15
+ }
16
+ }
17
+ ```
18
+
19
+ Protect routes that require a verified email:
20
+
21
+ ```ts
22
+ import { RequireAuth, EnsureEmailIsVerified } from '@rudderjs/auth'
23
+
24
+ router.get('/dashboard', RequireAuth(), EnsureEmailIsVerified(), handler)
25
+ ```
26
+
27
+ Generate a signed URL to send in an email:
28
+
29
+ ```ts
30
+ import { verificationUrl } from '@rudderjs/auth'
31
+
32
+ const url = verificationUrl(user)
33
+ // Sign-protected — calling it with a tampered signature returns 403
34
+ ```
35
+
36
+ Handle the click:
37
+
38
+ ```ts
39
+ import { handleEmailVerification } from '@rudderjs/auth'
40
+
41
+ router.get('/verify-email/:id/:hash', async (req, res) => {
42
+ await handleEmailVerification(req.params.id, req.params.hash, (id) => User.find(id))
43
+ res.redirect('/dashboard')
44
+ })
45
+ ```
46
+
47
+ ## Password reset
48
+
49
+ The `PasswordBroker` orchestrates token generation, email dispatch, and verification. A token repository persists the tokens.
50
+
51
+ ```ts
52
+ import { PasswordBroker, MemoryTokenRepository } from '@rudderjs/auth'
53
+
54
+ const broker = new PasswordBroker(new MemoryTokenRepository())
55
+ ```
56
+
57
+ In production, implement `TokenRepository` backed by your database:
58
+
59
+ ```ts
60
+ import type { TokenRepository } from '@rudderjs/auth'
61
+
62
+ class PrismaTokenRepository implements TokenRepository {
63
+ async create(email: string, token: string) { /* INSERT */ }
64
+ async findByEmailAndToken(email: string, token: string) { /* SELECT */ }
65
+ async delete(email: string) { /* DELETE */ }
66
+ async deleteExpired(thresholdMs: number) { /* DELETE WHERE created_at < ... */ }
67
+ }
68
+ ```
69
+
70
+ ## Pitfalls
71
+
72
+ ❌ **Don't** ship `MemoryTokenRepository` to production — tokens evaporate on restart, and multi-process / multi-worker setups never share state.
73
+
74
+ ✅ **Do** persist tokens via your ORM (Prisma/Drizzle) and run a scheduled cleanup of expired rows.
75
+
76
+ ❌ **Don't** assume `verificationUrl(user)` works without `APP_KEY`:
77
+
78
+ ```ts
79
+ // Throws if APP_KEY isn't set
80
+ const url = verificationUrl(user)
81
+ ```
82
+
83
+ ✅ **Do** set `APP_KEY` in `.env` (or call `Url.setKey('test-key')` in tests).
84
+
85
+ ❌ **Don't** roll a hand-crafted signature on the verification URL:
86
+
87
+ ```ts
88
+ const url = `/verify-email/${user.id}/${crypto.createHash(...)}`
89
+ ```
90
+
91
+ ✅ **Do** use `verificationUrl(user)` — it uses HMAC-SHA256 with timing-safe comparison via `@rudderjs/router`'s `Url`.
@@ -0,0 +1,110 @@
1
+ # Gates and Policies
2
+
3
+ `Gate` is the imperative authorization API; `Policy` classes group abilities per model.
4
+
5
+ ## Define abilities
6
+
7
+ ```ts
8
+ import { Gate } from '@rudderjs/auth'
9
+
10
+ Gate.define('manage-settings', (user) => user.role === 'admin')
11
+ Gate.define('edit-post', (user, post) => post.authorId === user.getAuthIdentifier())
12
+ ```
13
+
14
+ ## Check in route handlers
15
+
16
+ ```ts
17
+ // Returns boolean
18
+ if (await Gate.allows('manage-settings')) { /* ... */ }
19
+ if (await Gate.denies('edit-post', post)) { /* ... */ }
20
+
21
+ // Throws 403 on denial
22
+ await Gate.authorize('edit-post', post)
23
+ ```
24
+
25
+ `authorize` throws `AuthorizationError` which the framework maps to a `403` response.
26
+
27
+ ## Before callback
28
+
29
+ Runs before every gate check — useful for super-admins:
30
+
31
+ ```ts
32
+ Gate.before((user, ability) => {
33
+ if (user.role === 'super-admin') return true // allow everything
34
+ return null // fall through to normal checks
35
+ })
36
+ ```
37
+
38
+ Return `true` to allow, `false` to deny, `null` to fall through.
39
+
40
+ ## Model policies
41
+
42
+ ```ts
43
+ import { Policy } from '@rudderjs/auth'
44
+ import type { Authenticatable } from '@rudderjs/auth'
45
+
46
+ class PostPolicy extends Policy {
47
+ before(user: Authenticatable) {
48
+ if ((user as { role?: string }).role === 'admin') return true
49
+ return null
50
+ }
51
+
52
+ view(user: Authenticatable, post: Post) {
53
+ return post.isPublished || post.authorId === user.getAuthIdentifier()
54
+ }
55
+
56
+ update(user: Authenticatable, post: Post) {
57
+ return post.authorId === user.getAuthIdentifier()
58
+ }
59
+
60
+ delete(user: Authenticatable, post: Post) {
61
+ return post.authorId === user.getAuthIdentifier()
62
+ }
63
+ }
64
+
65
+ Gate.policy(Post, PostPolicy)
66
+ ```
67
+
68
+ Method names on the policy class match ability names. `Gate.authorize('update', post)` looks up `PostPolicy.update(user, post)`.
69
+
70
+ ## Pitfalls
71
+
72
+ ❌ **Don't** call `Gate.authorize` outside an auth context expecting it to throw 401:
73
+
74
+ ```ts
75
+ // In a job — no auth context, user is null, gate throws AuthorizationError as 403
76
+ await Gate.authorize('edit-post', post)
77
+ ```
78
+
79
+ ✅ **Do** check authentication first or scope the gate explicitly:
80
+
81
+ ```ts
82
+ await Gate.forUser(user).authorize('edit-post', post)
83
+ ```
84
+
85
+ ❌ **Don't** rely on policy autoloading from disk:
86
+
87
+ ```ts
88
+ // Putting app/Policies/PostPolicy.ts on disk does NOT auto-register it
89
+ ```
90
+
91
+ ✅ **Do** register policies in a service provider's `boot()`:
92
+
93
+ ```ts
94
+ // app/Providers/AppServiceProvider.ts
95
+ boot() {
96
+ Gate.policy(Post, PostPolicy)
97
+ }
98
+ ```
99
+
100
+ ❌ **Don't** return non-boolean from a `define` callback expecting it to count:
101
+
102
+ ```ts
103
+ Gate.define('edit-post', (user, post) => post.authorId) // truthy number, but not boolean
104
+ ```
105
+
106
+ ✅ **Do** return a boolean explicitly:
107
+
108
+ ```ts
109
+ Gate.define('edit-post', (user, post) => post.authorId === user.getAuthIdentifier())
110
+ ```
@@ -0,0 +1,121 @@
1
+ # Guards and Route Handlers
2
+
3
+ ## Reading the current user
4
+
5
+ Three equivalent ways:
6
+
7
+ ```ts
8
+ import { auth, Auth, RequireAuth } from '@rudderjs/auth'
9
+
10
+ // auth() helper — Laravel-style
11
+ router.get('/api/me', async (req, res) => {
12
+ const user = await auth().user()
13
+ if (!user) return res.status(401).json({ message: 'Unauthorized' })
14
+ res.json({ user })
15
+ })
16
+
17
+ // Auth facade
18
+ router.get('/api/profile', async (req, res) => {
19
+ if (await Auth.guest()) return res.status(401).json({ message: 'Unauthorized' })
20
+ res.json({ user: await Auth.user() })
21
+ })
22
+
23
+ // RequireAuth middleware — guarantees req.user
24
+ router.get('/api/dashboard', RequireAuth(), async (req, res) => {
25
+ res.json({ user: req.user })
26
+ })
27
+ ```
28
+
29
+ `Auth.user()` and `auth().user()` **soft-fail** outside the `AuthMiddleware` ALS context — they return `null`, never throw. This matches Laravel's `Auth::user()` semantics.
30
+
31
+ ## Login / register / logout
32
+
33
+ ```ts
34
+ router.post('/auth/login', async (req, res) => {
35
+ const { email, password } = req.body
36
+ const success = await auth().attempt({ email, password })
37
+ if (!success) return res.status(422).json({ message: 'Invalid credentials.' })
38
+ res.json({ user: await auth().user() })
39
+ })
40
+
41
+ router.post('/auth/register', async (req, res) => {
42
+ const user = await User.create({
43
+ name: req.body.name,
44
+ email: req.body.email,
45
+ password: req.body.password, // hashed automatically via Attribute mutator
46
+ })
47
+ await auth().login(user)
48
+ res.json({ user })
49
+ })
50
+
51
+ router.post('/auth/logout', RequireAuth(), async (req, res) => {
52
+ await auth().logout()
53
+ res.json({ message: 'Logged out.' })
54
+ })
55
+ ```
56
+
57
+ `attempt({ email, password })` runs `hashCheck(plain, hashed)` internally via the `EloquentUserProvider`.
58
+
59
+ ## RequireAuth vs RequireGuest
60
+
61
+ ```ts
62
+ router.get('/dashboard', RequireAuth(), handler) // 401 if not authenticated
63
+ router.get('/login', RequireGuest(), handler) // redirects authenticated users away
64
+ ```
65
+
66
+ ## Web vs API auth
67
+
68
+ | | Web | API |
69
+ |---|---|---|
70
+ | `req.user` | ✓ — populated by `AuthMiddleware` (auto-installed on `web` group) | ✗ — stateless by default |
71
+ | Session | ✓ — `sessionMiddleware` auto-installed on `web` | ✗ — don't add it globally |
72
+ | Per-route auth | Just use `RequireAuth()` | `RequireBearer()` + `scope(...)` from `@rudderjs/passport` |
73
+
74
+ ## Pitfalls
75
+
76
+ ❌ **Don't** add `sessionMiddleware` to `m.use(...)` (global):
77
+
78
+ ```ts
79
+ .withMiddleware((m) => {
80
+ m.use(sessionMiddleware) // breaks the "API is stateless" contract
81
+ })
82
+ ```
83
+
84
+ ✅ **Do** let `SessionProvider.boot()` install it on the `web` group only.
85
+
86
+ ❌ **Don't** expect `req.user` on api routes:
87
+
88
+ ```ts
89
+ router.get('/api/data', async (req, res) => {
90
+ console.log(req.user) // always undefined — AuthMiddleware doesn't run on api group
91
+ })
92
+ ```
93
+
94
+ ✅ **Do** use bearer auth per-route on api:
95
+
96
+ ```ts
97
+ import { RequireBearer, scope } from '@rudderjs/passport'
98
+
99
+ router.get('/api/data', RequireBearer(), scope('read'), async (req, res) => {
100
+ res.json({ user: req.user })
101
+ })
102
+ ```
103
+
104
+ ❌ **Don't** rely on `Auth.user()` outside `AuthMiddleware`:
105
+
106
+ ```ts
107
+ // In a queue job — no ALS context
108
+ const user = await Auth.user() // always null
109
+ ```
110
+
111
+ ✅ **Do** pass `userId` into the job and re-fetch:
112
+
113
+ ```ts
114
+ class SendWelcomeEmail extends Job {
115
+ constructor(private userId: number) { super() }
116
+ async handle() {
117
+ const user = await User.find(this.userId)
118
+ // …
119
+ }
120
+ }
121
+ ```
@@ -0,0 +1,104 @@
1
+ # Provider Setup
2
+
3
+ ## Install dependencies
4
+
5
+ ```bash
6
+ pnpm add @rudderjs/auth @rudderjs/session @rudderjs/hash
7
+ ```
8
+
9
+ Both `@rudderjs/session` and `@rudderjs/hash` are **required peer dependencies**.
10
+
11
+ ## Configure (`config/auth.ts`)
12
+
13
+ ```ts
14
+ import { User } from '../app/Models/User.js'
15
+ import type { AuthConfig } from '@rudderjs/auth'
16
+
17
+ export default {
18
+ defaults: {
19
+ guard: 'web',
20
+ },
21
+ guards: {
22
+ web: {
23
+ driver: 'session',
24
+ provider: 'users',
25
+ },
26
+ },
27
+ providers: {
28
+ users: {
29
+ driver: 'eloquent',
30
+ model: User,
31
+ },
32
+ },
33
+ } satisfies AuthConfig
34
+ ```
35
+
36
+ ## Register the provider (`bootstrap/providers.ts`)
37
+
38
+ `AuthProvider` is auto-discovered via `defaultProviders()` — nothing manual to add:
39
+
40
+ ```ts
41
+ import { defaultProviders } from '@rudderjs/core'
42
+
43
+ export default [
44
+ ...(await defaultProviders()),
45
+ // … your app providers
46
+ ]
47
+ ```
48
+
49
+ ## Make the User model authenticatable
50
+
51
+ ```ts
52
+ import { Model, Hidden } from '@rudderjs/orm'
53
+ import type { Authenticatable } from '@rudderjs/auth'
54
+
55
+ export class User extends Model implements Authenticatable {
56
+ static fillable = ['name', 'email', 'password']
57
+
58
+ @Hidden password = ''
59
+
60
+ getAuthIdentifier(): string { return String(this.id) }
61
+ getAuthPassword(): string { return this.password }
62
+ getRememberToken(): string | null { return null }
63
+ setRememberToken(_t: string): void {}
64
+ }
65
+ ```
66
+
67
+ The `@Hidden` decorator keeps `password` out of `toJSON()` output. The `EloquentUserProvider` calls `hashCheck()` (from `@rudderjs/hash`) on `getAuthPassword()`.
68
+
69
+ ## Pitfalls
70
+
71
+ ❌ **Don't** register `AuthProvider` before `HashProvider` / `SessionProvider`:
72
+
73
+ ```ts
74
+ export default [
75
+ AuthProvider, // boots before HashProvider — throws on first hash check
76
+ HashProvider,
77
+ SessionProvider,
78
+ ]
79
+ ```
80
+
81
+ ✅ **Do** use `defaultProviders()` — it orders the foundation/infrastructure stages correctly:
82
+
83
+ ```ts
84
+ export default [...(await defaultProviders())]
85
+ ```
86
+
87
+ ❌ **Don't** add `AuthMiddleware` globally via `m.use()`:
88
+
89
+ ```ts
90
+ .withMiddleware((m) => {
91
+ m.use(AuthMiddleware()) // crashes api routes — no session context
92
+ })
93
+ ```
94
+
95
+ ✅ **Do** let `AuthProvider.boot()` auto-install it on the `web` group only:
96
+
97
+ ```ts
98
+ // Nothing to do — AuthProvider handles it. For api auth, use RequireBearer()
99
+ // + scope(...) from @rudderjs/passport per-route.
100
+ ```
101
+
102
+ ❌ **Don't** cache `SessionGuard` instances inside `AuthManager` (legacy `_guards` Map):
103
+
104
+ The manager is a DI singleton; cached guards leak `_user` across requests. The fix is already in place — don't reintroduce.
package/dist/index.d.ts CHANGED
@@ -6,6 +6,7 @@ declare module '@rudderjs/contracts' {
6
6
  user?: AuthUser;
7
7
  }
8
8
  }
9
+ import './types/vike.js';
9
10
  export { Auth, auth } from './auth-manager.js';
10
11
  export { AuthManager, runWithAuth, currentAuth } from './auth-manager.js';
11
12
  export { SessionGuard } from './session-guard.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAA8B,MAAM,gBAAgB,CAAA;AAC5E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAE5D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAK9C,OAAO,QAAQ,qBAAqB,CAAC;IACnC,UAAU,UAAU;QAClB,IAAI,CAAC,EAAE,QAAQ,CAAA;KAChB;CACF;AAID,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAA;AAC9C,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AACzE,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACjD,OAAO,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AACxE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAA;AAC5D,OAAO,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAA;AAC3E,OAAO,EAAE,qBAAqB,EAAE,eAAe,EAAE,uBAAuB,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AACpH,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACjD,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAA;AAC9D,YAAY,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AAEhF,YAAY,EAAE,eAAe,EAAE,QAAQ,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AACpF,YAAY,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AACxD,YAAY,EAAE,eAAe,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAA;AACpG,YAAY,EAAE,UAAU,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AACxF,YAAY,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAetD;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,OAAO,GAAG,QAAQ,CAsBnD;AAID;;;GAGG;AACH,wBAAgB,cAAc,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,iBAAiB,CAuCpE;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,iBAAiB,CAoBjE;AAID;;;;;;;;;;;GAWG;AACH,qBAAa,YAAa,SAAQ,eAAe;IAC/C,QAAQ,IAAI,IAAI;IAgBV,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CA6B5B"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAA8B,MAAM,gBAAgB,CAAA;AAC5E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAE5D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAK9C,OAAO,QAAQ,qBAAqB,CAAC;IACnC,UAAU,UAAU;QAClB,IAAI,CAAC,EAAE,QAAQ,CAAA;KAChB;CACF;AAID,OAAO,iBAAiB,CAAA;AAIxB,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAA;AAC9C,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AACzE,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACjD,OAAO,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AACxE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAA;AAC5D,OAAO,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAA;AAC3E,OAAO,EAAE,qBAAqB,EAAE,eAAe,EAAE,uBAAuB,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AACpH,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACjD,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAA;AAC9D,YAAY,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AAEhF,YAAY,EAAE,eAAe,EAAE,QAAQ,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AACpF,YAAY,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AACxD,YAAY,EAAE,eAAe,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAA;AACpG,YAAY,EAAE,UAAU,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AACxF,YAAY,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAetD;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,OAAO,GAAG,QAAQ,CAsBnD;AAID;;;GAGG;AACH,wBAAgB,cAAc,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,iBAAiB,CAuCpE;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,iBAAiB,CAoBjE;AAID;;;;;;;;;;;GAWG;AACH,qBAAa,YAAa,SAAQ,eAAe;IAC/C,QAAQ,IAAI,IAAI;IAgBV,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAkC5B"}
package/dist/index.js CHANGED
@@ -1,5 +1,8 @@
1
1
  import { ServiceProvider, app, config, appendToGroup } from '@rudderjs/core';
2
2
  import { AuthManager, Auth, runWithAuth } from './auth-manager.js';
3
+ // Pulls in the Vike.PageContext.user augmentation so app code can read
4
+ // `pageContext.user` with full typing when this package is installed.
5
+ import './types/vike.js';
3
6
  // ─── Re-exports ───────────────────────────────────────────
4
7
  export { Auth, auth } from './auth-manager.js';
5
8
  export { AuthManager, runWithAuth, currentAuth } from './auth-manager.js';
@@ -179,6 +182,29 @@ export class AuthProvider extends ServiceProvider {
179
182
  // API routes opt into bearer auth with `RequireBearer()` from @rudderjs/passport
180
183
  // or `RequireAuth('api')` with a token-based guard.
181
184
  appendToGroup('web', AuthMiddleware());
185
+ // Register a Vike page-context enhancer that exposes the current user
186
+ // on `pageContext.user`. `@rudderjs/vite` is an optional peer — apps
187
+ // without it (e.g. API-only services) silently skip this registration.
188
+ await registerVikeUserEnhancer();
189
+ }
190
+ }
191
+ async function registerVikeUserEnhancer() {
192
+ try {
193
+ const mod = await import('@rudderjs/vite/page-context-enhancers').catch(() => null);
194
+ if (!mod?.registerPageContextEnhancer)
195
+ return;
196
+ mod.registerPageContextEnhancer(async (pageContext) => {
197
+ try {
198
+ const u = await Auth.user();
199
+ pageContext.user = u ? userToPlain(u) : null;
200
+ }
201
+ catch {
202
+ pageContext.user = null;
203
+ }
204
+ });
205
+ }
206
+ catch {
207
+ // Optional peer not installed — quietly skip.
182
208
  }
183
209
  }
184
210
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -14,6 +14,13 @@ export interface PasswordResetConfig {
14
14
  expire?: number;
15
15
  /** Seconds between reset requests for the same email (default: 60) */
16
16
  throttle?: number;
17
+ /**
18
+ * HMAC secret for hashing stored reset tokens.
19
+ * Defaults to the generic string 'password-reset' when omitted.
20
+ * Set this to your APP_KEY (or a derived value) so stored token
21
+ * hashes are bound to your app instance.
22
+ */
23
+ secret?: string;
17
24
  }
18
25
  export declare class PasswordBroker {
19
26
  private readonly tokens;
@@ -21,6 +28,7 @@ export declare class PasswordBroker {
21
28
  private readonly config;
22
29
  private readonly expire;
23
30
  private readonly throttle;
31
+ private readonly secret;
24
32
  constructor(tokens: TokenRepository, users: UserProvider, config?: PasswordResetConfig);
25
33
  /**
26
34
  * Send a password reset link.
@@ -1 +1 @@
1
- {"version":3,"file":"password-reset.d.ts","sourceRoot":"","sources":["../src/password-reset.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAInE,MAAM,WAAW,eAAe;IAC9B,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACpE,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,IAAI,CAAA;KAAE,GAAG,IAAI,CAAC,CAAA;IACvE,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACpC,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CAC/B;AAID,MAAM,MAAM,mBAAmB,GAC3B,iBAAiB,GACjB,gBAAgB,GAChB,cAAc,GACd,eAAe,GACf,eAAe,GACf,WAAW,CAAA;AAIf,MAAM,WAAW,mBAAmB;IAClC,yDAAyD;IACzD,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,sEAAsE;IACtE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAID,qBAAa,cAAc;IAKvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,MAAM;IANzB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAQ;IAC/B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAQ;gBAGd,MAAM,EAAE,eAAe,EACvB,KAAK,EAAE,YAAY,EACnB,MAAM,GAAE,mBAAwB;IAMnD;;;;OAIG;IACG,aAAa,CACjB,WAAW,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,EAC9B,QAAQ,EAAE,CAAC,IAAI,EAAE,eAAe,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GAChE,OAAO,CAAC,mBAAmB,CAAC;IA0B/B;;;;OAIG;IACG,KAAK,CACT,WAAW,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,EAC/D,QAAQ,EAAE,CAAC,IAAI,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GACnE,OAAO,CAAC,mBAAmB,CAAC;IAwB/B,OAAO,CAAC,SAAS;IAIjB,OAAO,CAAC,WAAW;CAMpB;AAID,qBAAa,qBAAsB,YAAW,eAAe;IAC3D,OAAO,CAAC,KAAK,CAAyE;IAEhF,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAIpE,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,IAAI,CAAA;KAAE,GAAG,IAAI,CAAC;IAKvE,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIpC,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;CAMrC"}
1
+ {"version":3,"file":"password-reset.d.ts","sourceRoot":"","sources":["../src/password-reset.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAInE,MAAM,WAAW,eAAe;IAC9B,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACpE,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,IAAI,CAAA;KAAE,GAAG,IAAI,CAAC,CAAA;IACvE,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACpC,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CAC/B;AAID,MAAM,MAAM,mBAAmB,GAC3B,iBAAiB,GACjB,gBAAgB,GAChB,cAAc,GACd,eAAe,GACf,eAAe,GACf,WAAW,CAAA;AAIf,MAAM,WAAW,mBAAmB;IAClC,yDAAyD;IACzD,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,sEAAsE;IACtE,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAID,qBAAa,cAAc;IAMvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAPzB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAQ;IAC/B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAQ;IACjC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAQ;gBAGZ,MAAM,EAAE,eAAe,EACvB,KAAK,EAAE,YAAY,EACnB,MAAM,GAAE,mBAAwB;IAOnD;;;;OAIG;IACG,aAAa,CACjB,WAAW,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,EAC9B,QAAQ,EAAE,CAAC,IAAI,EAAE,eAAe,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GAChE,OAAO,CAAC,mBAAmB,CAAC;IA0B/B;;;;OAIG;IACG,KAAK,CACT,WAAW,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,EAC/D,QAAQ,EAAE,CAAC,IAAI,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GACnE,OAAO,CAAC,mBAAmB,CAAC;IAwB/B,OAAO,CAAC,SAAS;IAIjB,OAAO,CAAC,WAAW;CAMpB;AAID,qBAAa,qBAAsB,YAAW,eAAe;IAC3D,OAAO,CAAC,KAAK,CAAyE;IAEhF,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAIpE,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,IAAI,CAAA;KAAE,GAAG,IAAI,CAAC;IAKvE,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIpC,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;CAMrC"}
@@ -6,12 +6,14 @@ export class PasswordBroker {
6
6
  config;
7
7
  expire;
8
8
  throttle;
9
+ secret;
9
10
  constructor(tokens, users, config = {}) {
10
11
  this.tokens = tokens;
11
12
  this.users = users;
12
13
  this.config = config;
13
14
  this.expire = config.expire ?? 60;
14
15
  this.throttle = config.throttle ?? 60;
16
+ this.secret = config.secret ?? 'password-reset';
15
17
  }
16
18
  /**
17
19
  * Send a password reset link.
@@ -67,7 +69,7 @@ export class PasswordBroker {
67
69
  return 'PASSWORD_RESET';
68
70
  }
69
71
  hashToken(token) {
70
- return createHmac('sha256', 'password-reset').update(token).digest('hex');
72
+ return createHmac('sha256', this.secret).update(token).digest('hex');
71
73
  }
72
74
  verifyToken(plain, hashed) {
73
75
  const computed = Buffer.from(this.hashToken(plain), 'hex');
@@ -1 +1 @@
1
- {"version":3,"file":"password-reset.js","sourceRoot":"","sources":["../src/password-reset.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"password-reset.js","sourceRoot":"","sources":["../src/password-reset.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Vike module augmentation — declares `pageContext.user` for apps using
3
+ * `@rudderjs/auth`. The runtime value is populated by the page-context
4
+ * enhancer registered in `AuthProvider.boot()`.
5
+ *
6
+ * Apps that don't install `@rudderjs/vite`'s `+onCreatePageContext` hook
7
+ * (i.e. don't extend `@rudderjs/vite/config` from their `pages/+config.ts`)
8
+ * will see `undefined` at runtime — the type is intentionally optional.
9
+ */
10
+ import type { AuthUser } from '../contracts.js';
11
+ declare global {
12
+ namespace Vike {
13
+ interface PageContext {
14
+ /**
15
+ * The currently authenticated user, populated by `@rudderjs/auth`'s
16
+ * page-context enhancer. `null` when no session is active or the
17
+ * request is outside the `AuthMiddleware` async-local context.
18
+ */
19
+ user?: AuthUser | null;
20
+ }
21
+ }
22
+ }
23
+ export {};
24
+ //# sourceMappingURL=vike.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vike.d.ts","sourceRoot":"","sources":["../../src/types/vike.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAA;AAE/C,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,IAAI,CAAC;QACb,UAAU,WAAW;YACnB;;;;eAIG;YACH,IAAI,CAAC,EAAE,QAAQ,GAAG,IAAI,CAAA;SACvB;KACF;CACF;AAED,OAAO,EAAE,CAAA"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Vike module augmentation — declares `pageContext.user` for apps using
3
+ * `@rudderjs/auth`. The runtime value is populated by the page-context
4
+ * enhancer registered in `AuthProvider.boot()`.
5
+ *
6
+ * Apps that don't install `@rudderjs/vite`'s `+onCreatePageContext` hook
7
+ * (i.e. don't extend `@rudderjs/vite/config` from their `pages/+config.ts`)
8
+ * will see `undefined` at runtime — the type is intentionally optional.
9
+ */
10
+ export {};
11
+ //# sourceMappingURL=vike.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vike.js","sourceRoot":"","sources":["../../src/types/vike.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
@@ -1 +1 @@
1
- {"version":3,"file":"verification.d.ts","sourceRoot":"","sources":["../src/verification.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAC5D,OAAO,KAAK,EAAE,eAAe,EAAY,MAAM,gBAAgB,CAAA;AAI/D;;;;;;;;;GASG;AACH,MAAM,WAAW,eAAe;IAC9B,gBAAgB,IAAI,OAAO,CAAA;IAC3B,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACpC,uBAAuB,IAAI,MAAM,CAAA;CAClC;AAED,mDAAmD;AACnD,wBAAgB,eAAe,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,IAAI,eAAe,GAAG,eAAe,CAOxF;AAID;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,IAAI,iBAAiB,CAiBzD;AAID;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,eAAe,GAAG;IAAE,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAAC,iBAAiB,CAAC,IAAI,MAAM,CAAA;CAAE,GAAG,MAAM,CAQtH;AAID;;;;;;;;;;;GAWG;AACH,wBAAsB,uBAAuB,CAC3C,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,GACpF,OAAO,CAAC,OAAO,CAAC,CAclB"}
1
+ {"version":3,"file":"verification.d.ts","sourceRoot":"","sources":["../src/verification.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAC5D,OAAO,KAAK,EAAE,eAAe,EAAY,MAAM,gBAAgB,CAAA;AAI/D;;;;;;;;;GASG;AACH,MAAM,WAAW,eAAe;IAC9B,gBAAgB,IAAI,OAAO,CAAA;IAC3B,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACpC,uBAAuB,IAAI,MAAM,CAAA;CAClC;AAED,mDAAmD;AACnD,wBAAgB,eAAe,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,IAAI,eAAe,GAAG,eAAe,CAOxF;AAID;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,IAAI,iBAAiB,CAiBzD;AAID;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,eAAe,GAAG;IAAE,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAAC,iBAAiB,CAAC,IAAI,MAAM,CAAA;CAAE,GAAG,MAAM,CAQtH;AAID;;;;;;;;;;;GAWG;AACH,wBAAsB,uBAAuB,CAC3C,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,GACpF,OAAO,CAAC,OAAO,CAAC,CAgBlB"}
@@ -1,4 +1,4 @@
1
- import { createHash } from 'node:crypto';
1
+ import { createHash, timingSafeEqual as cryptoTimingSafeEqual } from 'node:crypto';
2
2
  import { Url } from '@rudderjs/router';
3
3
  /** Type guard for users that must verify email. */
4
4
  export function mustVerifyEmail(user) {
@@ -70,7 +70,9 @@ export async function handleEmailVerification(id, hash, findUser) {
70
70
  return false;
71
71
  const email = user.getEmailForVerification();
72
72
  const expected = _sha256(email);
73
- if (hash !== expected)
73
+ const hashBuf = Buffer.from(hash, 'hex');
74
+ const expectedBuf = Buffer.from(expected, 'hex');
75
+ if (hashBuf.length !== expectedBuf.length || !cryptoTimingSafeEqual(hashBuf, expectedBuf))
74
76
  return false;
75
77
  if (!user.hasVerifiedEmail()) {
76
78
  await user.markEmailAsVerified();
@@ -1 +1 @@
1
- {"version":3,"file":"verification.js","sourceRoot":"","sources":["../src/verification.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAA;AAsBtC,mDAAmD;AACnD,MAAM,UAAU,eAAe,CAAC,IAAa;IAC3C,MAAM,CAAC,GAAG,IAA+B,CAAA;IACzC,OAAO,CACL,OAAO,CAAC,CAAC,kBAAkB,CAAC,KAAK,UAAU;QAC3C,OAAO,CAAC,CAAC,qBAAqB,CAAC,KAAK,UAAU;QAC9C,OAAO,CAAC,CAAC,yBAAyB,CAAC,KAAK,UAAU,CACnD,CAAA;AACH,CAAC;AAED,gEAAgE;AAEhE;;;;;;;GAOG;AACH,MAAM,UAAU,qBAAqB;IACnC,OAAO,KAAK,UAAU,qBAAqB,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI;QACxD,MAAM,IAAI,GAAI,GAAsC,CAAC,IAAI,CAAA;QAEzD,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,eAAe,EAAE,CAAC,CAAA;YAClD,OAAM;QACR,CAAC;QAED,oDAAoD;QACpD,IAAI,IAAI,CAAC,iBAAiB,CAAC,KAAK,IAAI,IAAI,IAAI,CAAC,iBAAiB,CAAC,KAAK,SAAS,EAAE,CAAC;YAC9E,MAAM,IAAI,EAAE,CAAA;YACZ,OAAM;QACR,CAAC;QAED,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,qCAAqC,EAAE,CAAC,CAAA;IAC1E,CAAC,CAAA;AACH,CAAC;AAED,+DAA+D;AAE/D;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,eAAe,CAAC,IAA8E;IAC5G,MAAM,EAAE,GAAM,IAAI,CAAC,iBAAiB,EAAE,EAAE,IAAI,MAAM,CAAE,IAA2C,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAA;IAC5G,MAAM,KAAK,GAAG,IAAI,CAAC,uBAAuB,EAAE,CAAA;IAE5C,gDAAgD;IAChD,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,CAAA;IAE3B,OAAO,GAAG,CAAC,oBAAoB,CAAC,qBAAqB,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAA;AAC5E,CAAC;AAED,+DAA+D;AAE/D;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,EAAU,EACV,IAAY,EACZ,QAAqF;IAErF,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,EAAE,CAAC,CAAA;IAC/B,IAAI,CAAC,IAAI;QAAE,OAAO,KAAK,CAAA;IAEvB,MAAM,KAAK,GAAO,IAAI,CAAC,uBAAuB,EAAE,CAAA;IAChD,MAAM,QAAQ,GAAI,OAAO,CAAC,KAAK,CAAC,CAAA;IAEhC,IAAI,IAAI,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAA;IAEnC,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,EAAE,CAAC;QAC7B,MAAM,IAAI,CAAC,mBAAmB,EAAE,CAAA;IAClC,CAAC;IAED,OAAO,IAAI,CAAA;AACb,CAAC;AAED,+DAA+D;AAE/D,SAAS,OAAO,CAAC,KAAa;IAC5B,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;AACzD,CAAC"}
1
+ {"version":3,"file":"verification.js","sourceRoot":"","sources":["../src/verification.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rudderjs/auth",
3
- "version": "5.0.0",
3
+ "version": "5.1.0",
4
4
  "rudderjs": {
5
5
  "provider": "AuthProvider",
6
6
  "stage": "infrastructure",
@@ -44,14 +44,15 @@
44
44
  "./package.json": "./package.json"
45
45
  },
46
46
  "dependencies": {
47
- "@rudderjs/contracts": "^1.2.0",
48
- "@rudderjs/core": "^1.1.2"
47
+ "@rudderjs/contracts": "^1.6.0",
48
+ "@rudderjs/core": "^1.1.3"
49
49
  },
50
50
  "peerDependencies": {
51
51
  "@rudderjs/hash": "^1.0.1",
52
- "@rudderjs/router": "^1.1.2",
53
- "@rudderjs/session": "^1.0.4",
54
- "@rudderjs/view": "^1.0.1"
52
+ "@rudderjs/router": "^1.2.0",
53
+ "@rudderjs/session": "^1.1.0",
54
+ "@rudderjs/view": "^1.1.0",
55
+ "@rudderjs/vite": "^1.1.0"
55
56
  },
56
57
  "peerDependenciesMeta": {
57
58
  "@rudderjs/hash": {
@@ -65,6 +66,9 @@
65
66
  },
66
67
  "@rudderjs/view": {
67
68
  "optional": false
69
+ },
70
+ "@rudderjs/vite": {
71
+ "optional": true
68
72
  }
69
73
  },
70
74
  "devDependencies": {
@@ -72,9 +76,10 @@
72
76
  "reflect-metadata": "^0.2.2",
73
77
  "typescript": "^5.4.0",
74
78
  "@rudderjs/hash": "^1.0.1",
75
- "@rudderjs/router": "^1.1.2",
76
- "@rudderjs/session": "^1.0.4",
77
- "@rudderjs/view": "^1.0.1"
79
+ "@rudderjs/router": "^1.2.0",
80
+ "@rudderjs/session": "^1.1.0",
81
+ "@rudderjs/view": "^1.1.0",
82
+ "@rudderjs/vite": "^1.1.0"
78
83
  },
79
84
  "author": "Suleiman Shahbari",
80
85
  "scripts": {
@@ -1,6 +1,6 @@
1
1
  import '@/index.css'
2
2
  import { useState } from 'react'
3
- import { getCsrfToken } from '@rudderjs/middleware'
3
+ import { getCsrfToken } from '@rudderjs/middleware/client'
4
4
 
5
5
  // URL this view is served at — see Login.tsx for rationale.
6
6
  export const route = '/forgot-password'
@@ -1,7 +1,7 @@
1
1
  import '@/index.css'
2
2
  import { useState } from 'react'
3
3
  import { navigate } from 'vike/client/router'
4
- import { getCsrfToken } from '@rudderjs/middleware'
4
+ import { getCsrfToken } from '@rudderjs/middleware/client'
5
5
 
6
6
  // URL this view is served at — MUST match the controller route registered
7
7
  // by registerAuthRoutes() in the consumer project. If you override
@@ -1,7 +1,7 @@
1
1
  import '@/index.css'
2
2
  import { useState } from 'react'
3
3
  import { navigate } from 'vike/client/router'
4
- import { getCsrfToken } from '@rudderjs/middleware'
4
+ import { getCsrfToken } from '@rudderjs/middleware/client'
5
5
 
6
6
  // URL this view is served at — see Login.tsx for rationale.
7
7
  export const route = '/register'
@@ -1,6 +1,6 @@
1
1
  import '@/index.css'
2
2
  import { useState, useEffect } from 'react'
3
- import { getCsrfToken } from '@rudderjs/middleware'
3
+ import { getCsrfToken } from '@rudderjs/middleware/client'
4
4
 
5
5
  // URL this view is served at — see Login.tsx for rationale.
6
6
  export const route = '/reset-password'