@rudderjs/auth 0.2.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/LICENSE +21 -0
- package/README.md +109 -0
- package/boost/guidelines.md +137 -0
- package/dist/auth-manager.d.ts +40 -0
- package/dist/auth-manager.d.ts.map +1 -0
- package/dist/auth-manager.js +85 -0
- package/dist/auth-manager.js.map +1 -0
- package/dist/contracts.d.ts +27 -0
- package/dist/contracts.d.ts.map +1 -0
- package/dist/contracts.js +3 -0
- package/dist/contracts.js.map +1 -0
- package/dist/gate.d.ts +49 -0
- package/dist/gate.d.ts.map +1 -0
- package/dist/gate.js +181 -0
- package/dist/gate.js.map +1 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +123 -0
- package/dist/index.js.map +1 -0
- package/dist/password-reset.d.ts +56 -0
- package/dist/password-reset.d.ts.map +1 -0
- package/dist/password-reset.js +101 -0
- package/dist/password-reset.js.map +1 -0
- package/dist/providers.d.ts +20 -0
- package/dist/providers.d.ts.map +1 -0
- package/dist/providers.js +41 -0
- package/dist/providers.js.map +1 -0
- package/dist/session-guard.d.ts +21 -0
- package/dist/session-guard.d.ts.map +1 -0
- package/dist/session-guard.js +52 -0
- package/dist/session-guard.js.map +1 -0
- package/dist/verification.d.ts +58 -0
- package/dist/verification.d.ts.map +1 -0
- package/dist/verification.js +93 -0
- package/dist/verification.js.map +1 -0
- package/package.json +57 -0
- package/pages/react/forgot-password/+Page.tsx +64 -0
- package/pages/react/login/+Page.tsx +70 -0
- package/pages/react/login/+guard.ts +15 -0
- package/pages/react/register/+Page.tsx +78 -0
- package/pages/react/register/+guard.ts +15 -0
- package/pages/react/reset-password/+Page.tsx +118 -0
- package/pages/solid/forgot-password/+Page.tsx +62 -0
- package/pages/solid/login/+Page.tsx +66 -0
- package/pages/solid/login/+guard.ts +15 -0
- package/pages/solid/register/+Page.tsx +72 -0
- package/pages/solid/register/+guard.ts +15 -0
- package/pages/solid/reset-password/+Page.tsx +94 -0
- package/pages/vue/forgot-password/+Page.vue +60 -0
- package/pages/vue/login/+Page.vue +63 -0
- package/pages/vue/login/+guard.ts +15 -0
- package/pages/vue/register/+Page.vue +68 -0
- package/pages/vue/register/+guard.ts +15 -0
- package/pages/vue/reset-password/+Page.vue +93 -0
- package/schema/auth.drizzle.mysql.ts +48 -0
- package/schema/auth.drizzle.pg.ts +48 -0
- package/schema/auth.drizzle.sqlite.ts +48 -0
- package/schema/auth.prisma +50 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Suleiman Shahbari
|
|
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,109 @@
|
|
|
1
|
+
# @rudderjs/auth
|
|
2
|
+
|
|
3
|
+
Native authentication for RudderJS. Laravel-style guards, user providers, and Auth facade.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add @rudderjs/auth @rudderjs/hash @rudderjs/session
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Setup
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
// config/auth.ts
|
|
15
|
+
import { User } from '../app/Models/User.js'
|
|
16
|
+
|
|
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
|
+
},
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// bootstrap/providers.ts
|
|
30
|
+
import { session } from '@rudderjs/session'
|
|
31
|
+
import { hash } from '@rudderjs/hash'
|
|
32
|
+
import { auth } from '@rudderjs/auth'
|
|
33
|
+
|
|
34
|
+
export default [
|
|
35
|
+
session(configs.session),
|
|
36
|
+
hash(configs.hash),
|
|
37
|
+
auth(configs.auth),
|
|
38
|
+
]
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Usage
|
|
42
|
+
|
|
43
|
+
### Auth Facade
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
import { Auth } from '@rudderjs/auth'
|
|
47
|
+
|
|
48
|
+
// Attempt login
|
|
49
|
+
const success = await Auth.attempt({ email, password })
|
|
50
|
+
|
|
51
|
+
// Manual login/logout
|
|
52
|
+
Auth.login(user)
|
|
53
|
+
Auth.logout()
|
|
54
|
+
|
|
55
|
+
// Current user
|
|
56
|
+
const user = await Auth.user() // Authenticatable | null
|
|
57
|
+
const id = await Auth.id() // string | null
|
|
58
|
+
const ok = await Auth.check() // boolean
|
|
59
|
+
const no = await Auth.guest() // boolean
|
|
60
|
+
|
|
61
|
+
// Switch guard
|
|
62
|
+
Auth.guard('api').user()
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Middleware
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
import { AuthMiddleware, RequireAuth } from '@rudderjs/auth'
|
|
69
|
+
|
|
70
|
+
// Attach user to request (non-blocking)
|
|
71
|
+
Route.get('/profile', handler, [AuthMiddleware()])
|
|
72
|
+
|
|
73
|
+
// Require authentication (returns 401 if not logged in)
|
|
74
|
+
Route.post('/posts', handler, [RequireAuth()])
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Authenticatable Contract
|
|
78
|
+
|
|
79
|
+
Your User model must implement:
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
interface Authenticatable {
|
|
83
|
+
getAuthIdentifier(): string
|
|
84
|
+
getAuthPassword(): string
|
|
85
|
+
getRememberToken(): string | null
|
|
86
|
+
setRememberToken(token: string): void
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
The `EloquentUserProvider` auto-wraps ORM model records with these methods (mapping `id`, `password`, `rememberToken` fields).
|
|
91
|
+
|
|
92
|
+
## Architecture
|
|
93
|
+
|
|
94
|
+
- **Guards** determine *how* users are authenticated (session cookies, API tokens)
|
|
95
|
+
- **User Providers** determine *where* users are retrieved from (Eloquent model, raw DB)
|
|
96
|
+
- **Auth facade** delegates to the current guard via `AsyncLocalStorage`
|
|
97
|
+
- **AuthManager** creates guards + providers from config, one per request
|
|
98
|
+
|
|
99
|
+
### Built-in Guards
|
|
100
|
+
|
|
101
|
+
| Guard | Driver | Description |
|
|
102
|
+
|-------|--------|-------------|
|
|
103
|
+
| Session | `session` | Cookie-based auth via `@rudderjs/session` |
|
|
104
|
+
|
|
105
|
+
### Built-in Providers
|
|
106
|
+
|
|
107
|
+
| Provider | Driver | Description |
|
|
108
|
+
|----------|--------|-------------|
|
|
109
|
+
| Eloquent | `eloquent` | Uses `@rudderjs/orm` Model class |
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# @rudderjs/auth
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Full-featured authentication and authorization package for RudderJS. Provides session-based guards, an Eloquent user provider, password reset broker, email verification, and a Laravel-style Gate/Policy authorization system. Uses `AsyncLocalStorage` for request-scoped auth context, integrates with `@rudderjs/hash` for password checking and `@rudderjs/session` for cookie-based sessions.
|
|
6
|
+
|
|
7
|
+
## Key Patterns
|
|
8
|
+
|
|
9
|
+
### Authentication Guards
|
|
10
|
+
|
|
11
|
+
Guards implement the `Guard` contract (`user()`, `check()`, `attempt()`, `login()`, `logout()`). The `SessionGuard` is the built-in driver that stores `auth_user_id` in the session.
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
// config/auth.ts
|
|
15
|
+
export default {
|
|
16
|
+
defaults: { guard: 'web' },
|
|
17
|
+
guards: {
|
|
18
|
+
web: { driver: 'session', provider: 'users' },
|
|
19
|
+
},
|
|
20
|
+
providers: {
|
|
21
|
+
users: { driver: 'eloquent', model: User },
|
|
22
|
+
},
|
|
23
|
+
} satisfies AuthConfig
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Use `AuthMiddleware()` to populate `req.user` without blocking, or `RequireAuth()` to return 401 for unauthenticated requests:
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
router.get('/profile', RequireAuth(), async (req, res) => {
|
|
30
|
+
res.json(req.user) // AuthUser — id, name, email + extra fields
|
|
31
|
+
})
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Use the `Auth` facade inside route handlers (request-scoped via AsyncLocalStorage):
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
const success = await Auth.attempt({ email, password })
|
|
38
|
+
await Auth.login(user)
|
|
39
|
+
await Auth.logout()
|
|
40
|
+
const user = await Auth.user()
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Password Hashing
|
|
44
|
+
|
|
45
|
+
Auth delegates hashing to `@rudderjs/hash`. The hash provider **must** be registered before auth in the provider array:
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
// bootstrap/providers.ts
|
|
49
|
+
export default [hash(configs.hash), auth(configs.auth), ...]
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
The `EloquentUserProvider` calls `hashCheck(plain, hashed)` internally during `validateCredentials()`.
|
|
53
|
+
|
|
54
|
+
### Email Verification
|
|
55
|
+
|
|
56
|
+
Implement `MustVerifyEmail` on your User model:
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
class User extends Model implements Authenticatable, MustVerifyEmail {
|
|
60
|
+
hasVerifiedEmail() { return this.emailVerifiedAt !== null }
|
|
61
|
+
markEmailAsVerified() { this.emailVerifiedAt = new Date().toISOString(); return Promise.resolve() }
|
|
62
|
+
getEmailForVerification() { return this.email }
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Use the middleware and helpers:
|
|
67
|
+
|
|
68
|
+
```ts
|
|
69
|
+
router.get('/dashboard', RequireAuth(), EnsureEmailIsVerified(), handler)
|
|
70
|
+
|
|
71
|
+
// Generate a signed verification URL (requires @rudderjs/router)
|
|
72
|
+
const url = verificationUrl(user)
|
|
73
|
+
|
|
74
|
+
// Handle verification in the route
|
|
75
|
+
await handleEmailVerification(req.params.id, req.params.hash, (id) => User.find(id))
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Authorization (Gates/Policies)
|
|
79
|
+
|
|
80
|
+
Define abilities and policies, then check them anywhere:
|
|
81
|
+
|
|
82
|
+
```ts
|
|
83
|
+
// In a provider's boot()
|
|
84
|
+
Gate.define('edit-post', (user, post) => user.id === post.authorId)
|
|
85
|
+
Gate.policy(Post, PostPolicy)
|
|
86
|
+
Gate.before((user) => user.isAdmin ? true : undefined)
|
|
87
|
+
|
|
88
|
+
// In a handler
|
|
89
|
+
await Gate.authorize('edit-post', post) // throws AuthorizationError (403)
|
|
90
|
+
if (await Gate.allows('edit-post', post)) { ... }
|
|
91
|
+
|
|
92
|
+
// Scoped to a specific user
|
|
93
|
+
await Gate.forUser(user).allows('edit-post', post)
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Policies are classes with method names matching ability names:
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
class PostPolicy extends Policy {
|
|
100
|
+
before(user: Authenticatable) { return user.isAdmin ? true : undefined }
|
|
101
|
+
update(user: Authenticatable, post: Post) { return user.id === post.authorId }
|
|
102
|
+
delete(user: Authenticatable, post: Post) { return user.id === post.authorId }
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Common Pitfalls
|
|
107
|
+
|
|
108
|
+
- **Provider order matters**: `hash()` must come before `auth()` in the providers array, or boot throws.
|
|
109
|
+
- **Missing session**: `@rudderjs/session` is a required peer dep. The session middleware must run before `AuthMiddleware`.
|
|
110
|
+
- **Auth outside middleware context**: `Auth.user()` / `Gate.allows()` only work inside the `AuthMiddleware` scope (AsyncLocalStorage). Outside that scope you get "No auth context" errors.
|
|
111
|
+
- **Password stripped from AuthUser**: The `userToPlain()` helper removes `password` from `req.user` automatically.
|
|
112
|
+
- **Gate.reset()**: Only for testing. Gate state is static/global.
|
|
113
|
+
|
|
114
|
+
## Key Imports
|
|
115
|
+
|
|
116
|
+
```ts
|
|
117
|
+
// Provider factory
|
|
118
|
+
import { auth } from '@rudderjs/auth'
|
|
119
|
+
|
|
120
|
+
// Middleware
|
|
121
|
+
import { AuthMiddleware, RequireAuth, EnsureEmailIsVerified } from '@rudderjs/auth'
|
|
122
|
+
|
|
123
|
+
// Facades & managers
|
|
124
|
+
import { Auth, Gate, Policy, AuthorizationError } from '@rudderjs/auth'
|
|
125
|
+
|
|
126
|
+
// Password reset
|
|
127
|
+
import { PasswordBroker, MemoryTokenRepository } from '@rudderjs/auth'
|
|
128
|
+
|
|
129
|
+
// Email verification
|
|
130
|
+
import { verificationUrl, handleEmailVerification, mustVerifyEmail } from '@rudderjs/auth'
|
|
131
|
+
|
|
132
|
+
// User provider
|
|
133
|
+
import { EloquentUserProvider, toAuthenticatable } from '@rudderjs/auth'
|
|
134
|
+
|
|
135
|
+
// Types
|
|
136
|
+
import type { Authenticatable, AuthUser, Guard, UserProvider, AuthConfig, MustVerifyEmail } from '@rudderjs/auth'
|
|
137
|
+
```
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { Authenticatable, Guard } from './contracts.js';
|
|
2
|
+
import { type SessionStore } from './session-guard.js';
|
|
3
|
+
export interface AuthGuardConfig {
|
|
4
|
+
driver: 'session';
|
|
5
|
+
provider: string;
|
|
6
|
+
}
|
|
7
|
+
export interface AuthProviderConfig {
|
|
8
|
+
driver: 'eloquent';
|
|
9
|
+
model: unknown;
|
|
10
|
+
}
|
|
11
|
+
export interface AuthConfig {
|
|
12
|
+
defaults: {
|
|
13
|
+
guard: string;
|
|
14
|
+
};
|
|
15
|
+
guards: Record<string, AuthGuardConfig>;
|
|
16
|
+
providers: Record<string, AuthProviderConfig>;
|
|
17
|
+
}
|
|
18
|
+
export declare class AuthManager {
|
|
19
|
+
private readonly config;
|
|
20
|
+
private readonly hashCheck;
|
|
21
|
+
private readonly getSession;
|
|
22
|
+
private readonly _guards;
|
|
23
|
+
constructor(config: AuthConfig, hashCheck: (plain: string, hashed: string) => Promise<boolean>, getSession: () => SessionStore);
|
|
24
|
+
guard(name?: string): Guard;
|
|
25
|
+
private createProvider;
|
|
26
|
+
}
|
|
27
|
+
export declare function runWithAuth<T>(manager: AuthManager, fn: () => T): T;
|
|
28
|
+
export declare function currentAuth(): AuthManager;
|
|
29
|
+
export declare class Auth {
|
|
30
|
+
private static g;
|
|
31
|
+
static guard(name: string): Guard;
|
|
32
|
+
static attempt(credentials: Record<string, unknown>, remember?: boolean): Promise<boolean>;
|
|
33
|
+
static login(user: Authenticatable, remember?: boolean): Promise<void>;
|
|
34
|
+
static logout(): Promise<void>;
|
|
35
|
+
static user(): Promise<Authenticatable | null>;
|
|
36
|
+
static id(): Promise<string | null>;
|
|
37
|
+
static check(): Promise<boolean>;
|
|
38
|
+
static guest(): Promise<boolean>;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=auth-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-manager.d.ts","sourceRoot":"","sources":["../src/auth-manager.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,KAAK,EAAgB,MAAM,gBAAgB,CAAA;AAC1E,OAAO,EAAgB,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAKpE,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,SAAS,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,UAAU,CAAA;IAClB,KAAK,EAAE,OAAO,CAAA;CACf;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE;QACR,KAAK,EAAE,MAAM,CAAA;KACd,CAAA;IACD,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAA;IACvC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAA;CAC9C;AAID,qBAAa,WAAW;IAIpB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,UAAU;IAL7B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA2B;gBAGhC,MAAM,EAAE,UAAU,EAClB,SAAS,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,EAC9D,UAAU,EAAE,MAAM,YAAY;IAGjD,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,KAAK;IAqB3B,OAAO,CAAC,cAAc;CAavB;AAMD,wBAAgB,WAAW,CAAC,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAEnE;AAED,wBAAgB,WAAW,IAAI,WAAW,CAIzC;AAID,qBAAa,IAAI;IACf,OAAO,CAAC,MAAM,CAAC,CAAC;IAIhB,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK;IAIjC,MAAM,CAAC,OAAO,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,QAAQ,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAI1F,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,eAAe,EAAE,QAAQ,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAItE,MAAM,CAAC,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAI9B,MAAM,CAAC,IAAI,IAAI,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;IAI9C,MAAM,CAAC,EAAE,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAInC,MAAM,CAAC,KAAK,IAAI,OAAO,CAAC,OAAO,CAAC;IAIhC,MAAM,CAAC,KAAK,IAAI,OAAO,CAAC,OAAO,CAAC;CAGjC"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
2
|
+
import { SessionGuard } from './session-guard.js';
|
|
3
|
+
import { EloquentUserProvider } from './providers.js';
|
|
4
|
+
// ─── Auth Manager ─────────────────────────────────────────
|
|
5
|
+
export class AuthManager {
|
|
6
|
+
config;
|
|
7
|
+
hashCheck;
|
|
8
|
+
getSession;
|
|
9
|
+
_guards = new Map();
|
|
10
|
+
constructor(config, hashCheck, getSession) {
|
|
11
|
+
this.config = config;
|
|
12
|
+
this.hashCheck = hashCheck;
|
|
13
|
+
this.getSession = getSession;
|
|
14
|
+
}
|
|
15
|
+
guard(name) {
|
|
16
|
+
const guardName = name ?? this.config.defaults.guard;
|
|
17
|
+
const existing = this._guards.get(guardName);
|
|
18
|
+
if (existing)
|
|
19
|
+
return existing;
|
|
20
|
+
const guardConfig = this.config.guards[guardName];
|
|
21
|
+
if (!guardConfig)
|
|
22
|
+
throw new Error(`[RudderJS Auth] Guard "${guardName}" is not defined.`);
|
|
23
|
+
const provider = this.createProvider(guardConfig.provider);
|
|
24
|
+
let guard;
|
|
25
|
+
if (guardConfig.driver === 'session') {
|
|
26
|
+
guard = new SessionGuard(provider, this.getSession());
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
throw new Error(`[RudderJS Auth] Guard driver "${guardConfig.driver}" is not supported.`);
|
|
30
|
+
}
|
|
31
|
+
this._guards.set(guardName, guard);
|
|
32
|
+
return guard;
|
|
33
|
+
}
|
|
34
|
+
createProvider(name) {
|
|
35
|
+
const providerConfig = this.config.providers[name];
|
|
36
|
+
if (!providerConfig)
|
|
37
|
+
throw new Error(`[RudderJS Auth] User provider "${name}" is not defined.`);
|
|
38
|
+
if (providerConfig.driver === 'eloquent') {
|
|
39
|
+
return new EloquentUserProvider(providerConfig.model, this.hashCheck);
|
|
40
|
+
}
|
|
41
|
+
throw new Error(`[RudderJS Auth] Provider driver "${providerConfig.driver}" is not supported.`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
// ─── Request-scoped Auth (AsyncLocalStorage) ──────────────
|
|
45
|
+
const _als = new AsyncLocalStorage();
|
|
46
|
+
export function runWithAuth(manager, fn) {
|
|
47
|
+
return _als.run(manager, fn);
|
|
48
|
+
}
|
|
49
|
+
export function currentAuth() {
|
|
50
|
+
const m = _als.getStore();
|
|
51
|
+
if (!m)
|
|
52
|
+
throw new Error('[RudderJS Auth] No auth context. Use AuthMiddleware.');
|
|
53
|
+
return m;
|
|
54
|
+
}
|
|
55
|
+
// ─── Auth Facade ──────────────────────────────────────────
|
|
56
|
+
export class Auth {
|
|
57
|
+
static g(name) {
|
|
58
|
+
return currentAuth().guard(name);
|
|
59
|
+
}
|
|
60
|
+
static guard(name) {
|
|
61
|
+
return currentAuth().guard(name);
|
|
62
|
+
}
|
|
63
|
+
static attempt(credentials, remember) {
|
|
64
|
+
return this.g().attempt(credentials, remember);
|
|
65
|
+
}
|
|
66
|
+
static login(user, remember) {
|
|
67
|
+
return this.g().login(user, remember);
|
|
68
|
+
}
|
|
69
|
+
static logout() {
|
|
70
|
+
return this.g().logout();
|
|
71
|
+
}
|
|
72
|
+
static user() {
|
|
73
|
+
return this.g().user();
|
|
74
|
+
}
|
|
75
|
+
static id() {
|
|
76
|
+
return this.g().id();
|
|
77
|
+
}
|
|
78
|
+
static check() {
|
|
79
|
+
return this.g().check();
|
|
80
|
+
}
|
|
81
|
+
static guest() {
|
|
82
|
+
return this.g().guest();
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=auth-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-manager.js","sourceRoot":"","sources":["../src/auth-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export interface Authenticatable {
|
|
2
|
+
getAuthIdentifier(): string;
|
|
3
|
+
getAuthPassword(): string;
|
|
4
|
+
getRememberToken(): string | null;
|
|
5
|
+
setRememberToken(token: string): void;
|
|
6
|
+
}
|
|
7
|
+
export interface AuthUser {
|
|
8
|
+
id: string;
|
|
9
|
+
name: string;
|
|
10
|
+
email: string;
|
|
11
|
+
[key: string]: unknown;
|
|
12
|
+
}
|
|
13
|
+
export interface UserProvider {
|
|
14
|
+
retrieveById(id: string): Promise<Authenticatable | null>;
|
|
15
|
+
retrieveByCredentials(credentials: Record<string, unknown>): Promise<Authenticatable | null>;
|
|
16
|
+
validateCredentials(user: Authenticatable, credentials: Record<string, unknown>): Promise<boolean>;
|
|
17
|
+
}
|
|
18
|
+
export interface Guard {
|
|
19
|
+
user(): Promise<Authenticatable | null>;
|
|
20
|
+
id(): Promise<string | null>;
|
|
21
|
+
check(): Promise<boolean>;
|
|
22
|
+
guest(): Promise<boolean>;
|
|
23
|
+
attempt(credentials: Record<string, unknown>, remember?: boolean): Promise<boolean>;
|
|
24
|
+
login(user: Authenticatable, remember?: boolean): Promise<void>;
|
|
25
|
+
logout(): Promise<void>;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=contracts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contracts.d.ts","sourceRoot":"","sources":["../src/contracts.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,eAAe;IAC9B,iBAAiB,IAAI,MAAM,CAAA;IAC3B,eAAe,IAAI,MAAM,CAAA;IACzB,gBAAgB,IAAI,MAAM,GAAG,IAAI,CAAA;IACjC,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;CACtC;AAID,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACvB;AAID,MAAM,WAAW,YAAY;IAC3B,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAAA;IACzD,qBAAqB,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAAA;IAC5F,mBAAmB,CAAC,IAAI,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;CACnG;AAID,MAAM,WAAW,KAAK;IACpB,IAAI,IAAI,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAAA;IACvC,EAAE,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAA;IAC5B,KAAK,IAAI,OAAO,CAAC,OAAO,CAAC,CAAA;IACzB,KAAK,IAAI,OAAO,CAAC,OAAO,CAAC,CAAA;IACzB,OAAO,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,QAAQ,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IACnF,KAAK,CAAC,IAAI,EAAE,eAAe,EAAE,QAAQ,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC/D,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CACxB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contracts.js","sourceRoot":"","sources":["../src/contracts.ts"],"names":[],"mappings":"AAAA,6DAA6D"}
|
package/dist/gate.d.ts
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { Authenticatable } from './contracts.js';
|
|
2
|
+
type AbilityCallback = (user: Authenticatable, ...args: unknown[]) => boolean | Promise<boolean>;
|
|
3
|
+
type BeforeCallback = (user: Authenticatable, ability: string) => boolean | null | undefined | Promise<boolean | null | undefined>;
|
|
4
|
+
export declare abstract class Policy {
|
|
5
|
+
/**
|
|
6
|
+
* Run before any other check. Return true/false to short-circuit,
|
|
7
|
+
* or null/undefined to fall through to the specific method.
|
|
8
|
+
*/
|
|
9
|
+
before?(_user: Authenticatable): boolean | null | undefined | Promise<boolean | null | undefined>;
|
|
10
|
+
}
|
|
11
|
+
type PolicyClass = new () => Policy;
|
|
12
|
+
type ModelClass = abstract new (...args: any[]) => unknown;
|
|
13
|
+
export declare class Gate {
|
|
14
|
+
private static _abilities;
|
|
15
|
+
private static _policies;
|
|
16
|
+
private static _beforeCallbacks;
|
|
17
|
+
static define(ability: string, callback: AbilityCallback): void;
|
|
18
|
+
static before(callback: BeforeCallback): void;
|
|
19
|
+
static policy(model: ModelClass, policy: PolicyClass): void;
|
|
20
|
+
static allows(ability: string, ...args: unknown[]): Promise<boolean>;
|
|
21
|
+
static denies(ability: string, ...args: unknown[]): Promise<boolean>;
|
|
22
|
+
/**
|
|
23
|
+
* Check ability — throw 403 if denied.
|
|
24
|
+
*/
|
|
25
|
+
static authorize(ability: string, ...args: unknown[]): Promise<void>;
|
|
26
|
+
static forUser(user: Authenticatable): GateForUser;
|
|
27
|
+
private static resolveUser;
|
|
28
|
+
private static _check;
|
|
29
|
+
private static findPolicy;
|
|
30
|
+
private static callPolicy;
|
|
31
|
+
/** @internal — reset all definitions. Used for testing. */
|
|
32
|
+
static reset(): void;
|
|
33
|
+
}
|
|
34
|
+
declare class GateForUser {
|
|
35
|
+
private readonly user;
|
|
36
|
+
private readonly abilities;
|
|
37
|
+
private readonly policies;
|
|
38
|
+
private readonly beforeCallbacks;
|
|
39
|
+
constructor(user: Authenticatable, abilities: Map<string, AbilityCallback>, policies: Map<ModelClass, PolicyClass>, beforeCallbacks: BeforeCallback[]);
|
|
40
|
+
allows(ability: string, ...args: unknown[]): Promise<boolean>;
|
|
41
|
+
denies(ability: string, ...args: unknown[]): Promise<boolean>;
|
|
42
|
+
authorize(ability: string, ...args: unknown[]): Promise<void>;
|
|
43
|
+
}
|
|
44
|
+
export declare class AuthorizationError extends Error {
|
|
45
|
+
readonly status = 403;
|
|
46
|
+
constructor(message?: string);
|
|
47
|
+
}
|
|
48
|
+
export {};
|
|
49
|
+
//# sourceMappingURL=gate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gate.d.ts","sourceRoot":"","sources":["../src/gate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAKrD,KAAK,eAAe,GAAG,CAAC,IAAI,EAAE,eAAe,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;AAChG,KAAK,cAAc,GAAG,CAAC,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,KAAK,OAAO,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC,CAAA;AAIlI,8BAAsB,MAAM;IAC1B;;;OAGG;IACH,MAAM,CAAC,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC;CAClG;AAED,KAAK,WAAW,GAAG,UAAU,MAAM,CAAA;AAEnC,KAAK,UAAU,GAAG,QAAQ,MAAM,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,OAAO,CAAA;AAI1D,qBAAa,IAAI;IACf,OAAO,CAAC,MAAM,CAAC,UAAU,CAAqC;IAC9D,OAAO,CAAC,MAAM,CAAC,SAAS,CAAqC;IAC7D,OAAO,CAAC,MAAM,CAAC,gBAAgB,CAAuB;IAItD,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe,GAAG,IAAI;IAI/D,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,cAAc,GAAG,IAAI;IAI7C,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW,GAAG,IAAI;WAM9C,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC;WAM7D,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC;IAI1E;;OAEG;WACU,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ1E,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,eAAe,GAAG,WAAW;mBAM7B,WAAW;mBASX,MAAM;IAuB3B,OAAO,CAAC,MAAM,CAAC,UAAU;mBAiBJ,UAAU;IAqB/B,2DAA2D;IAC3D,MAAM,CAAC,KAAK,IAAI,IAAI;CAKrB;AAID,cAAM,WAAW;IAEb,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,eAAe;gBAHf,IAAI,EAAE,eAAe,EACrB,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,EACvC,QAAQ,EAAE,GAAG,CAAC,UAAU,EAAE,WAAW,CAAC,EACtC,eAAe,EAAE,cAAc,EAAE;IAG9C,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC;IAkC7D,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC;IAI7D,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CAKpE;AAID,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,QAAQ,CAAC,MAAM,OAAM;gBAET,OAAO,SAAiC;CAIrD"}
|