@veap/auth 0.0.0-stage → 0.1.1
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 +167 -2
- package/dist/actions/auth.actions.d.ts +23 -0
- package/dist/actions/auth.actions.js +40 -0
- package/dist/actions/index.d.ts +1 -0
- package/dist/actions/index.js +1 -0
- package/dist/client/auth.context.d.ts +29 -0
- package/dist/client/auth.context.js +64 -0
- package/dist/client/index.d.ts +1 -0
- package/dist/client/index.js +1 -0
- package/dist/common/augment.d.ts +26 -0
- package/dist/common/augment.js +63 -0
- package/dist/common/context.d.ts +30 -0
- package/dist/common/context.js +36 -0
- package/dist/common/index.d.ts +7 -0
- package/dist/common/index.js +7 -0
- package/dist/common/logic.d.ts +64 -0
- package/dist/common/logic.js +133 -0
- package/dist/common/registry.d.ts +28 -0
- package/dist/common/registry.js +76 -0
- package/dist/common/routes.d.ts +3 -0
- package/dist/common/routes.js +2 -0
- package/dist/common/tokens.d.ts +10 -0
- package/dist/common/tokens.js +8 -0
- package/dist/common/types.d.ts +178 -0
- package/dist/common/types.js +9 -0
- package/dist/crypto/aes-cipher.d.ts +8 -0
- package/dist/crypto/aes-cipher.js +12 -0
- package/dist/crypto/bcrypt-hasher.d.ts +12 -0
- package/dist/crypto/bcrypt-hasher.js +37 -0
- package/dist/crypto/contracts.d.ts +36 -0
- package/dist/crypto/contracts.js +3 -0
- package/dist/crypto/encryption.d.ts +18 -0
- package/dist/crypto/encryption.js +69 -0
- package/dist/crypto/index.d.ts +6 -0
- package/dist/crypto/index.js +6 -0
- package/dist/crypto/password.d.ts +19 -0
- package/dist/crypto/password.js +27 -0
- package/dist/crypto/token-generator.d.ts +10 -0
- package/dist/crypto/token-generator.js +25 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +11 -0
- package/dist/migrations/0001_create_auth_tables.d.ts +4 -0
- package/dist/migrations/0001_create_auth_tables.js +122 -0
- package/dist/migrations/index.d.ts +4 -0
- package/dist/migrations/index.js +7 -0
- package/dist/models/EmailVerification.d.ts +23 -0
- package/dist/models/EmailVerification.js +19 -0
- package/dist/models/PasswordResetSession.d.ts +25 -0
- package/dist/models/PasswordResetSession.js +21 -0
- package/dist/models/Permission.d.ts +20 -0
- package/dist/models/Permission.js +19 -0
- package/dist/models/Role.d.ts +20 -0
- package/dist/models/Role.js +19 -0
- package/dist/models/Session.d.ts +22 -0
- package/dist/models/Session.js +21 -0
- package/dist/models/User.d.ts +32 -0
- package/dist/models/User.js +31 -0
- package/dist/models/index.d.ts +6 -0
- package/dist/models/index.js +6 -0
- package/dist/models.d.ts +1 -0
- package/dist/models.js +1 -0
- package/dist/passwords/contracts.d.ts +28 -0
- package/dist/passwords/contracts.js +2 -0
- package/dist/passwords/index.d.ts +4 -0
- package/dist/passwords/index.js +4 -0
- package/dist/passwords/password-reset.facade.d.ts +14 -0
- package/dist/passwords/password-reset.facade.js +57 -0
- package/dist/passwords/password-reset.repository.d.ts +10 -0
- package/dist/passwords/password-reset.repository.js +39 -0
- package/dist/passwords/password-reset.service.d.ts +38 -0
- package/dist/passwords/password-reset.service.js +242 -0
- package/dist/providers/auth.provider.d.ts +9 -0
- package/dist/providers/auth.provider.js +199 -0
- package/dist/providers/index.d.ts +2 -0
- package/dist/providers/index.js +2 -0
- package/dist/providers/setup.d.ts +7 -0
- package/dist/providers/setup.js +29 -0
- package/dist/rbac/contracts.d.ts +75 -0
- package/dist/rbac/contracts.js +4 -0
- package/dist/rbac/index.d.ts +4 -0
- package/dist/rbac/index.js +4 -0
- package/dist/rbac/rbac.facade.d.ts +23 -0
- package/dist/rbac/rbac.facade.js +85 -0
- package/dist/rbac/rbac.repository.d.ts +30 -0
- package/dist/rbac/rbac.repository.js +137 -0
- package/dist/rbac/rbac.service.d.ts +35 -0
- package/dist/rbac/rbac.service.js +143 -0
- package/dist/server.d.ts +3 -0
- package/dist/server.js +3 -0
- package/dist/session/auth.service.d.ts +35 -0
- package/dist/session/auth.service.js +207 -0
- package/dist/session/contracts.d.ts +33 -0
- package/dist/session/contracts.js +2 -0
- package/dist/session/index.d.ts +5 -0
- package/dist/session/index.js +5 -0
- package/dist/session/session.facade.d.ts +14 -0
- package/dist/session/session.facade.js +75 -0
- package/dist/session/session.repository.d.ts +15 -0
- package/dist/session/session.repository.js +55 -0
- package/dist/session/session.service.d.ts +63 -0
- package/dist/session/session.service.js +221 -0
- package/dist/users/contracts.d.ts +33 -0
- package/dist/users/contracts.js +2 -0
- package/dist/users/index.d.ts +4 -0
- package/dist/users/index.js +4 -0
- package/dist/users/user.facade.d.ts +28 -0
- package/dist/users/user.facade.js +92 -0
- package/dist/users/user.repository.d.ts +16 -0
- package/dist/users/user.repository.js +60 -0
- package/dist/users/user.service.d.ts +80 -0
- package/dist/users/user.service.js +201 -0
- package/dist/validation/index.d.ts +90 -0
- package/dist/validation/index.js +46 -0
- package/dist/verification/contracts.d.ts +25 -0
- package/dist/verification/contracts.js +2 -0
- package/dist/verification/index.d.ts +4 -0
- package/dist/verification/index.js +4 -0
- package/dist/verification/verification.facade.d.ts +10 -0
- package/dist/verification/verification.facade.js +49 -0
- package/dist/verification/verification.repository.d.ts +7 -0
- package/dist/verification/verification.repository.js +23 -0
- package/dist/verification/verification.service.d.ts +44 -0
- package/dist/verification/verification.service.js +122 -0
- package/package.json +84 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Damian Miller
|
|
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
CHANGED
|
@@ -1,3 +1,168 @@
|
|
|
1
|
-
|
|
1
|
+
[](https://github.com/veapjs/veap-auth/actions/workflows/CI.yml)
|
|
2
|
+
[](https://github.com/veapjs/veap-auth/actions/workflows/RELEASE.yml)
|
|
3
|
+
[](https://www.npmjs.com/package/@veap/auth)
|
|
2
4
|
|
|
3
|
-
|
|
5
|
+
# @veap/auth
|
|
6
|
+
|
|
7
|
+
Production-ready authentication, session management, RBAC, and cryptographic
|
|
8
|
+
adapters for Veap and Next.js applications.
|
|
9
|
+
|
|
10
|
+
## Overview
|
|
11
|
+
|
|
12
|
+
`@veap/auth` provides a modular authentication engine adhering to clean
|
|
13
|
+
architecture principles modeled after `@veap/kernel`. It decouples domain entities (users, sessions, roles,
|
|
14
|
+
permissions) and ports (hasher, token generator, cipher) into dedicated functional modules. It includes ready-to-use Next.js Server
|
|
15
|
+
Actions, automatic database migrations, and Active Record adapters powered by
|
|
16
|
+
`@veap/database`.
|
|
17
|
+
|
|
18
|
+
## Architecture & Structure
|
|
19
|
+
|
|
20
|
+
Following the same modular, domain-driven structure as `@veap/kernel`:
|
|
21
|
+
|
|
22
|
+
```text
|
|
23
|
+
src/
|
|
24
|
+
├── actions/ # Next.js Server Actions (signIn, signUp, signOut, etc.)
|
|
25
|
+
├── client/ # React hooks and context (useUser, AuthProvider)
|
|
26
|
+
├── common/ # Common context, routes, registry, and augmentation
|
|
27
|
+
├── crypto/ # Cryptography ports and adapters (bcrypt, AES, tokens)
|
|
28
|
+
├── migrations/ # Database migration definitions
|
|
29
|
+
├── models/ # ActiveRecord database models (User, Role, Session, etc.)
|
|
30
|
+
├── passwords/ # Password reset repositories, service, and facades
|
|
31
|
+
├── providers/ # AuthServiceProvider and bootstrap setup
|
|
32
|
+
├── rbac/ # Role-based access control repositories, service, and facades
|
|
33
|
+
├── session/ # Session repository, SessionService, and AuthService
|
|
34
|
+
├── users/ # User repository, UserService, and facades
|
|
35
|
+
├── validation/ # Zod input validation schemas
|
|
36
|
+
├── index.ts # Main barrel entrypoint
|
|
37
|
+
├── server.ts # Server-only utilities entrypoint
|
|
38
|
+
├── client.tsx # React client entrypoint
|
|
39
|
+
├── actions.ts # Server actions entrypoint
|
|
40
|
+
└── models.ts # ActiveRecord models entrypoint
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Features
|
|
44
|
+
|
|
45
|
+
- **Multi-layer authentication**: Secure password hashing with bcrypt, session
|
|
46
|
+
token generation via `@oslojs/crypto`, and AES secret encryption.
|
|
47
|
+
- **Session management**: Database-backed session persistence with automatic
|
|
48
|
+
token hashing, TTL expiry, and sliding-window extension.
|
|
49
|
+
- **Role-Based Access Control (RBAC)**: Fine-grained roles and permissions
|
|
50
|
+
associated with users through many-to-many database relations.
|
|
51
|
+
- **Next.js Server Actions**: First-class `signIn`, `signUp`, `signOut`, and
|
|
52
|
+
`getCurrentSession` actions returning typed `Result` objects.
|
|
53
|
+
- **Automated migrations**: Self-bootstrapping migrations for users, sessions,
|
|
54
|
+
roles, permissions, password reset requests, and email verification.
|
|
55
|
+
- **Client & React hooks**: Lightweight `useUser()` hook and `AuthProvider`
|
|
56
|
+
for responsive user sessions.
|
|
57
|
+
|
|
58
|
+
## Installation
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
# Using bun
|
|
62
|
+
bun add @veap/auth @veap/kernel @veap/database
|
|
63
|
+
|
|
64
|
+
# Using pnpm
|
|
65
|
+
pnpm add @veap/auth @veap/kernel @veap/database
|
|
66
|
+
|
|
67
|
+
# Using npm
|
|
68
|
+
npm install @veap/auth @veap/kernel @veap/database
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Usage
|
|
72
|
+
|
|
73
|
+
### Register in Application Builder
|
|
74
|
+
|
|
75
|
+
Include `AuthServiceProvider` in your application composition root:
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
import { Application } from "@veap/kernel";
|
|
79
|
+
import { DatabaseServiceProvider } from "@veap/database";
|
|
80
|
+
import { AuthServiceProvider } from "@veap/auth";
|
|
81
|
+
|
|
82
|
+
export const app = Application.configure()
|
|
83
|
+
.use(DatabaseServiceProvider)
|
|
84
|
+
.use(
|
|
85
|
+
new AuthServiceProvider(undefined, {
|
|
86
|
+
autoMigrate: true, // Automatically applies auth tables on boot
|
|
87
|
+
}),
|
|
88
|
+
)
|
|
89
|
+
.create();
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Sign In & Sign Out with Server Actions
|
|
93
|
+
|
|
94
|
+
Authenticate users in server components or server actions:
|
|
95
|
+
|
|
96
|
+
```ts
|
|
97
|
+
"use server";
|
|
98
|
+
|
|
99
|
+
import { signIn, signOut, getCurrentSession } from "@veap/auth";
|
|
100
|
+
|
|
101
|
+
export async function handleLogin(formData: FormData) {
|
|
102
|
+
const email = formData.get("email") as string;
|
|
103
|
+
const password = formData.get("password") as string;
|
|
104
|
+
|
|
105
|
+
const result = await signIn({ email, password });
|
|
106
|
+
|
|
107
|
+
if (!result.success) {
|
|
108
|
+
return { error: result.error?.message || "Invalid credentials" };
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return { user: result.data.user };
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export async function handleLogout() {
|
|
115
|
+
await signOut();
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export async function getActiveUser() {
|
|
119
|
+
const session = await getCurrentSession();
|
|
120
|
+
return session?.user ?? null;
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Querying Auth Models Directly
|
|
125
|
+
|
|
126
|
+
Interact with Active Record models provided by `@veap/auth/models`:
|
|
127
|
+
|
|
128
|
+
```ts
|
|
129
|
+
import { User, Role } from "@veap/auth/models";
|
|
130
|
+
import { hashPassword } from "@veap/auth/server";
|
|
131
|
+
|
|
132
|
+
// Create a new user with hashed credentials
|
|
133
|
+
const user = await User.create({
|
|
134
|
+
name: "Jane Doe",
|
|
135
|
+
email: "jane@example.com",
|
|
136
|
+
password: await hashPassword("securePassword123"),
|
|
137
|
+
recovery_code: Buffer.from("recovery-key-bytes"),
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
// Check roles and permissions
|
|
141
|
+
const adminRole = await Role.query().where("name", "admin").first();
|
|
142
|
+
if (adminRole) {
|
|
143
|
+
await user.roles().attach(adminRole.id);
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Subpath Exports
|
|
148
|
+
|
|
149
|
+
| Export Path | Content |
|
|
150
|
+
| ----------------------- | --------------------------------------------------------------------- |
|
|
151
|
+
| `@veap/auth` | Core actions (`signIn`, `signOut`), provider, context, and schemas |
|
|
152
|
+
| `@veap/auth/client` | React client components, context, and `useUser` hook |
|
|
153
|
+
| `@veap/auth/server` | Server cryptographic utilities (`hashPassword`, `verifyPasswordHash`) |
|
|
154
|
+
| `@veap/auth/actions` | Next.js Server Actions directly exportable for actions boundaries |
|
|
155
|
+
| `@veap/auth/models` | Active Record models (`User`, `Session`, `Role`, `Permission`) |
|
|
156
|
+
| `@veap/auth/migrations` | Knex migrations for authentication tables |
|
|
157
|
+
|
|
158
|
+
## Documentation
|
|
159
|
+
|
|
160
|
+
For full guides and authentication customization, visit:
|
|
161
|
+
|
|
162
|
+
- **Official Website**: [https://veap.pl](https://veap.pl)
|
|
163
|
+
- **Documentation**: [https://veap.pl/docs](https://veap.pl/docs)
|
|
164
|
+
- **GitHub Repository**: [https://github.com/veapjs/veap-auth](https://github.com/veapjs/veap-auth)
|
|
165
|
+
|
|
166
|
+
## License
|
|
167
|
+
|
|
168
|
+
MIT
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type Result } from "@veap/kernel";
|
|
2
|
+
import type { AuthResponse, SessionFlags } from "../common/index.js";
|
|
3
|
+
import type { LoginInput, RegisterInput } from "../validation/index.js";
|
|
4
|
+
export declare function signIn(data: LoginInput): Promise<Result<AuthResponse>>;
|
|
5
|
+
export declare function signUp(data: RegisterInput): Promise<{
|
|
6
|
+
success: false;
|
|
7
|
+
error: import("@veap/kernel").AppErrorJson;
|
|
8
|
+
data?: never;
|
|
9
|
+
} | {
|
|
10
|
+
success: true;
|
|
11
|
+
data: AuthResponse;
|
|
12
|
+
error?: never;
|
|
13
|
+
}>;
|
|
14
|
+
export declare function finalizeLogin(userId: string, flags: SessionFlags): Promise<{
|
|
15
|
+
success: false;
|
|
16
|
+
error: import("@veap/kernel").AppErrorJson;
|
|
17
|
+
data?: never;
|
|
18
|
+
} | {
|
|
19
|
+
success: true;
|
|
20
|
+
data: AuthResponse;
|
|
21
|
+
error?: never;
|
|
22
|
+
}>;
|
|
23
|
+
export declare function signOut(): Promise<Result<void>>;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use server";
|
|
2
|
+
import { app, handleActionError, ok } from "@veap/kernel";
|
|
3
|
+
import { AuthService } from "../session/auth.service.js";
|
|
4
|
+
export async function signIn(data) {
|
|
5
|
+
try {
|
|
6
|
+
const authService = await app(AuthService);
|
|
7
|
+
return ok(await authService.signIn(data));
|
|
8
|
+
}
|
|
9
|
+
catch (e) {
|
|
10
|
+
return handleActionError(e, "Auth:SignIn");
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export async function signUp(data) {
|
|
14
|
+
try {
|
|
15
|
+
const authService = await app(AuthService);
|
|
16
|
+
return ok(await authService.signUp(data));
|
|
17
|
+
}
|
|
18
|
+
catch (e) {
|
|
19
|
+
return handleActionError(e, "Auth:SignUp");
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export async function finalizeLogin(userId, flags) {
|
|
23
|
+
try {
|
|
24
|
+
const authService = await app(AuthService);
|
|
25
|
+
return ok(await authService.finalizeLogin(userId, flags));
|
|
26
|
+
}
|
|
27
|
+
catch (e) {
|
|
28
|
+
return handleActionError(e, "Auth:FinalizeLogin");
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
export async function signOut() {
|
|
32
|
+
try {
|
|
33
|
+
const authService = await app(AuthService);
|
|
34
|
+
await authService.signOut();
|
|
35
|
+
return ok(undefined);
|
|
36
|
+
}
|
|
37
|
+
catch (e) {
|
|
38
|
+
return handleActionError(e, "Auth:SignOut");
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./auth.actions.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./auth.actions.js";
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
import { type AuthRoutesConfig } from "../common/routes.js";
|
|
3
|
+
import type { AuthSession } from "../common/types.js";
|
|
4
|
+
export interface AuthContextValue {
|
|
5
|
+
user: AuthSession["user"] | null | undefined;
|
|
6
|
+
session: AuthSession["session"] | null | undefined;
|
|
7
|
+
prefix: string;
|
|
8
|
+
isLoading: boolean;
|
|
9
|
+
refetchUser: () => Promise<void>;
|
|
10
|
+
routes: AuthRoutesConfig;
|
|
11
|
+
}
|
|
12
|
+
export declare const AuthContext: import("react").Context<AuthContextValue | undefined>;
|
|
13
|
+
export declare const PathPrefixContext: import("react").Context<string>;
|
|
14
|
+
export interface AuthProviderProps {
|
|
15
|
+
children: ReactNode;
|
|
16
|
+
initialSession?: AuthSession | null;
|
|
17
|
+
prefix?: string;
|
|
18
|
+
routes?: AuthRoutesConfig;
|
|
19
|
+
}
|
|
20
|
+
export declare function AuthProvider({ children, initialSession, prefix, routes, }: AuthProviderProps): import("react").JSX.Element;
|
|
21
|
+
/**
|
|
22
|
+
* Hook to access configured authentication route URLs on the client.
|
|
23
|
+
*/
|
|
24
|
+
export declare function useAuthRoutes(): AuthRoutesConfig;
|
|
25
|
+
/**
|
|
26
|
+
* Hook for user management on the client.
|
|
27
|
+
* @returns Returns an object with user data and functions for managing it.
|
|
28
|
+
*/
|
|
29
|
+
export declare function useUser(): AuthContextValue;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { createContext, useContext, useEffect, useState, } from "react";
|
|
4
|
+
import { DEFAULT_AUTH_ROUTES, } from "../common/routes.js";
|
|
5
|
+
export const AuthContext = createContext(undefined);
|
|
6
|
+
export const PathPrefixContext = createContext("/app");
|
|
7
|
+
export function AuthProvider({ children, initialSession, prefix = "/app", routes = DEFAULT_AUTH_ROUTES, }) {
|
|
8
|
+
const [user, setUser] = useState(initialSession?.user ?? null);
|
|
9
|
+
const [session, setSession] = useState(initialSession?.session ?? null);
|
|
10
|
+
const [isLoading, setIsLoading] = useState(!initialSession);
|
|
11
|
+
const refetchUser = async () => {
|
|
12
|
+
try {
|
|
13
|
+
setIsLoading(true);
|
|
14
|
+
const res = await fetch("/api/auth/me", { credentials: "same-origin" });
|
|
15
|
+
if (res.ok) {
|
|
16
|
+
const data = await res.json();
|
|
17
|
+
setUser(data.user);
|
|
18
|
+
setSession(data.session);
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
setUser(null);
|
|
22
|
+
setSession(null);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
setUser(null);
|
|
27
|
+
setSession(null);
|
|
28
|
+
}
|
|
29
|
+
finally {
|
|
30
|
+
setIsLoading(false);
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
useEffect(() => {
|
|
34
|
+
if (!initialSession) {
|
|
35
|
+
refetchUser();
|
|
36
|
+
}
|
|
37
|
+
}, [initialSession]);
|
|
38
|
+
return (_jsx(AuthContext.Provider, { value: {
|
|
39
|
+
user,
|
|
40
|
+
session,
|
|
41
|
+
prefix,
|
|
42
|
+
isLoading,
|
|
43
|
+
refetchUser,
|
|
44
|
+
routes,
|
|
45
|
+
}, children: _jsx(PathPrefixContext.Provider, { value: prefix, children: children }) }));
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Hook to access configured authentication route URLs on the client.
|
|
49
|
+
*/
|
|
50
|
+
export function useAuthRoutes() {
|
|
51
|
+
const context = useContext(AuthContext);
|
|
52
|
+
return context?.routes ?? DEFAULT_AUTH_ROUTES;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Hook for user management on the client.
|
|
56
|
+
* @returns Returns an object with user data and functions for managing it.
|
|
57
|
+
*/
|
|
58
|
+
export function useUser() {
|
|
59
|
+
const context = useContext(AuthContext);
|
|
60
|
+
if (!context) {
|
|
61
|
+
throw new Error("useUser must be used within AuthProvider");
|
|
62
|
+
}
|
|
63
|
+
return { ...context };
|
|
64
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./auth.context.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./auth.context.js";
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { AuthCallbackRegistry } from "./registry.js";
|
|
2
|
+
import type { FullUser, PasswordResetSession, Session, User } from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* REGISTRIES FOR MODULAR EXTENSIONS
|
|
5
|
+
*/
|
|
6
|
+
export type IdentityAugmenter = (user: User) => Promise<Partial<FullUser>>;
|
|
7
|
+
export type SessionAugmenter = (session: Session) => Promise<Partial<Session>>;
|
|
8
|
+
export type PasswordResetSessionAugmenter = (session: PasswordResetSession) => Promise<Partial<PasswordResetSession>>;
|
|
9
|
+
export declare const identityAugmenters: AuthCallbackRegistry<IdentityAugmenter>;
|
|
10
|
+
export declare const sessionAugmenters: AuthCallbackRegistry<SessionAugmenter>;
|
|
11
|
+
export declare const passwordResetSessionAugmenters: AuthCallbackRegistry<PasswordResetSessionAugmenter>;
|
|
12
|
+
export declare function registerIdentityAugmenter(augmenter: IdentityAugmenter): void;
|
|
13
|
+
export declare function registerIdentityAugmenter(id: string, augmenter: IdentityAugmenter): void;
|
|
14
|
+
export declare function unregisterIdentityAugmenter(idOrAugmenter: string | IdentityAugmenter): boolean;
|
|
15
|
+
export declare function registerSessionAugmenter(augmenter: SessionAugmenter): void;
|
|
16
|
+
export declare function registerSessionAugmenter(id: string, augmenter: SessionAugmenter): void;
|
|
17
|
+
export declare function unregisterSessionAugmenter(idOrAugmenter: string | SessionAugmenter): boolean;
|
|
18
|
+
export declare function registerPasswordResetSessionAugmenter(augmenter: PasswordResetSessionAugmenter): void;
|
|
19
|
+
export declare function registerPasswordResetSessionAugmenter(id: string, augmenter: PasswordResetSessionAugmenter): void;
|
|
20
|
+
export declare function unregisterPasswordResetSessionAugmenter(idOrAugmenter: string | PasswordResetSessionAugmenter): boolean;
|
|
21
|
+
/**
|
|
22
|
+
* EXECUTION FUNCTIONS
|
|
23
|
+
*/
|
|
24
|
+
export declare function augmentUser(user: User, coreRbacData?: Record<string, any>): Promise<FullUser>;
|
|
25
|
+
export declare function augmentSession(session: Session): Promise<Session>;
|
|
26
|
+
export declare function augmentPasswordResetSession(session: PasswordResetSession): Promise<PasswordResetSession>;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { AuthCallbackRegistry } from "./registry.js";
|
|
2
|
+
const globalForAugment = globalThis;
|
|
3
|
+
export const identityAugmenters = globalForAugment.__VEAP_IDENTITY_AUGMENTERS__ ??
|
|
4
|
+
new AuthCallbackRegistry();
|
|
5
|
+
export const sessionAugmenters = globalForAugment.__VEAP_SESSION_AUGMENTERS__ ??
|
|
6
|
+
new AuthCallbackRegistry();
|
|
7
|
+
export const passwordResetSessionAugmenters = globalForAugment.__VEAP_PASSWORD_RESET_SESSION_AUGMENTERS__ ??
|
|
8
|
+
new AuthCallbackRegistry();
|
|
9
|
+
globalForAugment.__VEAP_IDENTITY_AUGMENTERS__ = identityAugmenters;
|
|
10
|
+
globalForAugment.__VEAP_SESSION_AUGMENTERS__ = sessionAugmenters;
|
|
11
|
+
globalForAugment.__VEAP_PASSWORD_RESET_SESSION_AUGMENTERS__ =
|
|
12
|
+
passwordResetSessionAugmenters;
|
|
13
|
+
export function registerIdentityAugmenter(idOrAugmenter, augmenter) {
|
|
14
|
+
identityAugmenters.register(idOrAugmenter, augmenter);
|
|
15
|
+
}
|
|
16
|
+
export function unregisterIdentityAugmenter(idOrAugmenter) {
|
|
17
|
+
return identityAugmenters.unregister(idOrAugmenter);
|
|
18
|
+
}
|
|
19
|
+
export function registerSessionAugmenter(idOrAugmenter, augmenter) {
|
|
20
|
+
sessionAugmenters.register(idOrAugmenter, augmenter);
|
|
21
|
+
}
|
|
22
|
+
export function unregisterSessionAugmenter(idOrAugmenter) {
|
|
23
|
+
return sessionAugmenters.unregister(idOrAugmenter);
|
|
24
|
+
}
|
|
25
|
+
export function registerPasswordResetSessionAugmenter(idOrAugmenter, augmenter) {
|
|
26
|
+
passwordResetSessionAugmenters.register(idOrAugmenter, augmenter);
|
|
27
|
+
}
|
|
28
|
+
export function unregisterPasswordResetSessionAugmenter(idOrAugmenter) {
|
|
29
|
+
return passwordResetSessionAugmenters.unregister(idOrAugmenter);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* EXECUTION FUNCTIONS
|
|
33
|
+
*/
|
|
34
|
+
export async function augmentUser(user, coreRbacData) {
|
|
35
|
+
let currentUser = { ...user, ...(coreRbacData || {}) };
|
|
36
|
+
for (const augmenter of identityAugmenters) {
|
|
37
|
+
const data = await augmenter(currentUser);
|
|
38
|
+
currentUser = { ...currentUser, ...data };
|
|
39
|
+
}
|
|
40
|
+
return currentUser;
|
|
41
|
+
}
|
|
42
|
+
export async function augmentSession(session) {
|
|
43
|
+
let currentSession = { ...session };
|
|
44
|
+
for (const augmenter of sessionAugmenters) {
|
|
45
|
+
const data = await augmenter(currentSession);
|
|
46
|
+
const existingFlags = currentSession.flags || {};
|
|
47
|
+
const newFlags = data?.flags || {};
|
|
48
|
+
currentSession = {
|
|
49
|
+
...currentSession,
|
|
50
|
+
...data,
|
|
51
|
+
flags: { ...existingFlags, ...newFlags },
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
return currentSession;
|
|
55
|
+
}
|
|
56
|
+
export async function augmentPasswordResetSession(session) {
|
|
57
|
+
let currentSession = { ...session };
|
|
58
|
+
for (const augmenter of passwordResetSessionAugmenters) {
|
|
59
|
+
const data = await augmenter(currentSession);
|
|
60
|
+
currentSession = { ...currentSession, ...data };
|
|
61
|
+
}
|
|
62
|
+
return currentSession;
|
|
63
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type AuthRoutesConfig } from "./routes.js";
|
|
2
|
+
export interface AuthContext {
|
|
3
|
+
user: any;
|
|
4
|
+
session: any;
|
|
5
|
+
rbac: any;
|
|
6
|
+
passwordReset: any;
|
|
7
|
+
emailVerification: any;
|
|
8
|
+
auth: any;
|
|
9
|
+
routes?: AuthRoutesConfig;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Binds the resolved auth services. Called once by the composition root.
|
|
13
|
+
*/
|
|
14
|
+
export declare function bindAuthContext(context: AuthContext): void;
|
|
15
|
+
/**
|
|
16
|
+
* Check whether auth context is currently bound.
|
|
17
|
+
*/
|
|
18
|
+
export declare function isAuthContextBound(): boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Returns the bound auth services.
|
|
21
|
+
*
|
|
22
|
+
* @throws If the auth service provider has not booted yet.
|
|
23
|
+
*/
|
|
24
|
+
export declare function authContext(): AuthContext & {
|
|
25
|
+
routes: AuthRoutesConfig;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Resolves currently configured auth routes, falling back to defaults.
|
|
29
|
+
*/
|
|
30
|
+
export declare function getAuthRoutes(): AuthRoutesConfig;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { DEFAULT_AUTH_ROUTES } from "./routes.js";
|
|
2
|
+
const globalForAuthContext = globalThis;
|
|
3
|
+
/**
|
|
4
|
+
* Binds the resolved auth services. Called once by the composition root.
|
|
5
|
+
*/
|
|
6
|
+
export function bindAuthContext(context) {
|
|
7
|
+
globalForAuthContext.__VEAP_AUTH_CONTEXT__ = {
|
|
8
|
+
...context,
|
|
9
|
+
routes: context.routes || DEFAULT_AUTH_ROUTES,
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Check whether auth context is currently bound.
|
|
14
|
+
*/
|
|
15
|
+
export function isAuthContextBound() {
|
|
16
|
+
return globalForAuthContext.__VEAP_AUTH_CONTEXT__ !== undefined;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Returns the bound auth services.
|
|
20
|
+
*
|
|
21
|
+
* @throws If the auth service provider has not booted yet.
|
|
22
|
+
*/
|
|
23
|
+
export function authContext() {
|
|
24
|
+
const context = globalForAuthContext.__VEAP_AUTH_CONTEXT__;
|
|
25
|
+
if (!context) {
|
|
26
|
+
throw new Error("[Auth] Context is not bound. AuthServiceProvider must boot before the auth facades are used.");
|
|
27
|
+
}
|
|
28
|
+
return context;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Resolves currently configured auth routes, falling back to defaults.
|
|
32
|
+
*/
|
|
33
|
+
export function getAuthRoutes() {
|
|
34
|
+
const context = globalForAuthContext.__VEAP_AUTH_CONTEXT__;
|
|
35
|
+
return context?.routes || DEFAULT_AUTH_ROUTES;
|
|
36
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { augmentSession, augmentUser, registerIdentityAugmenter, registerPasswordResetSessionAugmenter, registerSessionAugmenter, unregisterIdentityAugmenter, unregisterPasswordResetSessionAugmenter, unregisterSessionAugmenter } from "./augment.js";
|
|
2
|
+
import { AuthCallbackRegistry } from "./registry.js";
|
|
3
|
+
import type { AuthResponse, FullUser, Session, User, UserPermission, UserRole } from "./types.js";
|
|
4
|
+
/**
|
|
5
|
+
* Registry for login validators (e.g. 2FA module)
|
|
6
|
+
*/
|
|
7
|
+
export type AuthValidator = (userId: string) => Promise<AuthResponse | null>;
|
|
8
|
+
/**
|
|
9
|
+
* Registry for Security Requirements (e.g. checking if 2FA is needed for a session)
|
|
10
|
+
*/
|
|
11
|
+
export type SecurityRequirement = (session: Session, user: FullUser,
|
|
12
|
+
/**
|
|
13
|
+
* Request path the security check is running for ("/app/jobs", "/", ...).
|
|
14
|
+
* Lets a requirement exempt the route that resolves its own gate (e.g. an
|
|
15
|
+
* onboarding wizard) and prevents redirect loops.
|
|
16
|
+
*/
|
|
17
|
+
path?: string) => Promise<{
|
|
18
|
+
satisfied: boolean;
|
|
19
|
+
redirect?: string;
|
|
20
|
+
} | null>;
|
|
21
|
+
/**
|
|
22
|
+
* Registry for password reset validators (e.g. 2FA module requiring check during reset)
|
|
23
|
+
*/
|
|
24
|
+
export type PasswordResetValidator = (userId: string) => Promise<AuthResponse | null>;
|
|
25
|
+
/**
|
|
26
|
+
* Registry for email verification validators
|
|
27
|
+
*/
|
|
28
|
+
export type EmailVerificationValidator = (userId: string) => Promise<AuthResponse | null>;
|
|
29
|
+
export declare const authValidators: AuthCallbackRegistry<AuthValidator>;
|
|
30
|
+
export declare const securityRequirements: AuthCallbackRegistry<SecurityRequirement>;
|
|
31
|
+
export declare const passwordResetValidators: AuthCallbackRegistry<PasswordResetValidator>;
|
|
32
|
+
export declare const emailVerificationValidators: AuthCallbackRegistry<EmailVerificationValidator>;
|
|
33
|
+
export declare function registerAuthValidator(validator: AuthValidator): void;
|
|
34
|
+
export declare function registerAuthValidator(id: string, validator: AuthValidator): void;
|
|
35
|
+
export declare function unregisterAuthValidator(idOrValidator: string | AuthValidator): boolean;
|
|
36
|
+
export declare function registerPasswordResetValidator(validator: PasswordResetValidator): void;
|
|
37
|
+
export declare function registerPasswordResetValidator(id: string, validator: PasswordResetValidator): void;
|
|
38
|
+
export declare function unregisterPasswordResetValidator(idOrValidator: string | PasswordResetValidator): boolean;
|
|
39
|
+
export declare function registerEmailVerificationValidator(validator: EmailVerificationValidator): void;
|
|
40
|
+
export declare function registerEmailVerificationValidator(id: string, validator: EmailVerificationValidator): void;
|
|
41
|
+
export declare function unregisterEmailVerificationValidator(idOrValidator: string | EmailVerificationValidator): boolean;
|
|
42
|
+
export { augmentSession, augmentUser, registerIdentityAugmenter, registerPasswordResetSessionAugmenter, registerSessionAugmenter, unregisterIdentityAugmenter, unregisterPasswordResetSessionAugmenter, unregisterSessionAugmenter, };
|
|
43
|
+
export declare function registerSecurityRequirement(requirement: SecurityRequirement): void;
|
|
44
|
+
export declare function registerSecurityRequirement(id: string, requirement: SecurityRequirement): void;
|
|
45
|
+
export declare function unregisterSecurityRequirement(idOrRequirement: string | SecurityRequirement): boolean;
|
|
46
|
+
export declare function runPasswordResetValidators(userId: string): Promise<AuthResponse | null>;
|
|
47
|
+
export declare function runEmailVerificationValidators(userId: string): Promise<AuthResponse | null>;
|
|
48
|
+
/**
|
|
49
|
+
* Checks if the current session satisfies all registered security requirements.
|
|
50
|
+
*/
|
|
51
|
+
export declare function checkSecurity(session: Session, user: FullUser, requiredRoles?: UserRole[], requiredPermissions?: UserPermission[], fallbackRedirect?: string,
|
|
52
|
+
/** Request path this check runs for; forwarded to modular requirements. */
|
|
53
|
+
path?: string): Promise<{
|
|
54
|
+
satisfied: boolean;
|
|
55
|
+
redirect: string | undefined;
|
|
56
|
+
} | {
|
|
57
|
+
satisfied: boolean;
|
|
58
|
+
redirect?: undefined;
|
|
59
|
+
}>;
|
|
60
|
+
/**
|
|
61
|
+
* Performs full augmentation on a user by merging core RBAC roles/permissions
|
|
62
|
+
* and running all registered modular identity augmenters.
|
|
63
|
+
*/
|
|
64
|
+
export declare function performFullUserAugmentation(user: User, session?: Session): Promise<FullUser>;
|