@spfn/auth 0.1.0-alpha.0 → 0.1.0-alpha.86
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 +320 -12
- package/dist/adapters/nextjs/api.d.ts +446 -0
- package/dist/adapters/nextjs/api.js +3279 -0
- package/dist/adapters/nextjs/api.js.map +1 -0
- package/dist/adapters/nextjs/server.d.ts +246 -0
- package/dist/adapters/nextjs/server.js +3645 -0
- package/dist/adapters/nextjs/server.js.map +1 -0
- package/dist/client.d.ts +2 -0
- package/dist/client.js +1 -0
- package/dist/client.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +9098 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/api/auth-codes-verify.d.ts +37 -0
- package/dist/lib/api/auth-codes-verify.js +2949 -0
- package/dist/lib/api/auth-codes-verify.js.map +1 -0
- package/dist/lib/api/auth-codes.d.ts +37 -0
- package/dist/lib/api/auth-codes.js +2949 -0
- package/dist/lib/api/auth-codes.js.map +1 -0
- package/dist/lib/api/auth-exists.d.ts +38 -0
- package/dist/lib/api/auth-exists.js +2949 -0
- package/dist/lib/api/auth-exists.js.map +1 -0
- package/dist/lib/api/auth-invitations-accept.d.ts +38 -0
- package/dist/lib/api/auth-invitations-accept.js +2883 -0
- package/dist/lib/api/auth-invitations-accept.js.map +1 -0
- package/dist/lib/api/auth-invitations-cancel.d.ts +37 -0
- package/dist/lib/api/auth-invitations-cancel.js +2883 -0
- package/dist/lib/api/auth-invitations-cancel.js.map +1 -0
- package/dist/lib/api/auth-invitations-delete.d.ts +36 -0
- package/dist/lib/api/auth-invitations-delete.js +2883 -0
- package/dist/lib/api/auth-invitations-delete.js.map +1 -0
- package/dist/lib/api/auth-invitations-resend.d.ts +37 -0
- package/dist/lib/api/auth-invitations-resend.js +2883 -0
- package/dist/lib/api/auth-invitations-resend.js.map +1 -0
- package/dist/lib/api/auth-invitations.d.ts +109 -0
- package/dist/lib/api/auth-invitations.js +2887 -0
- package/dist/lib/api/auth-invitations.js.map +1 -0
- package/dist/lib/api/auth-keys-rotate.d.ts +37 -0
- package/dist/lib/api/auth-keys-rotate.js +2949 -0
- package/dist/lib/api/auth-keys-rotate.js.map +1 -0
- package/dist/lib/api/auth-login.d.ts +39 -0
- package/dist/lib/api/auth-login.js +2949 -0
- package/dist/lib/api/auth-login.js.map +1 -0
- package/dist/lib/api/auth-logout.d.ts +36 -0
- package/dist/lib/api/auth-logout.js +2949 -0
- package/dist/lib/api/auth-logout.js.map +1 -0
- package/dist/lib/api/auth-me.d.ts +50 -0
- package/dist/lib/api/auth-me.js +2949 -0
- package/dist/lib/api/auth-me.js.map +1 -0
- package/dist/lib/api/auth-password.d.ts +36 -0
- package/dist/lib/api/auth-password.js +2949 -0
- package/dist/lib/api/auth-password.js.map +1 -0
- package/dist/lib/api/auth-register.d.ts +38 -0
- package/dist/lib/api/auth-register.js +2949 -0
- package/dist/lib/api/auth-register.js.map +1 -0
- package/dist/lib/api/index.d.ts +356 -0
- package/dist/lib/api/index.js +3261 -0
- package/dist/lib/api/index.js.map +1 -0
- package/dist/lib/config.d.ts +70 -0
- package/dist/lib/config.js +64 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/contracts/auth.d.ts +302 -0
- package/dist/lib/contracts/auth.js +2951 -0
- package/dist/lib/contracts/auth.js.map +1 -0
- package/dist/lib/contracts/index.d.ts +3 -0
- package/dist/lib/contracts/index.js +3190 -0
- package/dist/lib/contracts/index.js.map +1 -0
- package/dist/lib/contracts/invitation.d.ts +243 -0
- package/dist/lib/contracts/invitation.js +2883 -0
- package/dist/lib/contracts/invitation.js.map +1 -0
- package/dist/lib/crypto.d.ts +76 -0
- package/dist/lib/crypto.js +127 -0
- package/dist/lib/crypto.js.map +1 -0
- package/dist/lib/index.d.ts +4 -0
- package/dist/lib/index.js +313 -0
- package/dist/lib/index.js.map +1 -0
- package/dist/lib/session.d.ts +68 -0
- package/dist/lib/session.js +126 -0
- package/dist/lib/session.js.map +1 -0
- package/dist/lib/types/api.d.ts +45 -0
- package/dist/lib/types/api.js +1 -0
- package/dist/lib/types/api.js.map +1 -0
- package/dist/lib/types/index.d.ts +3 -0
- package/dist/lib/types/index.js +2647 -0
- package/dist/lib/types/index.js.map +1 -0
- package/dist/lib/types/schemas.d.ts +45 -0
- package/dist/lib/types/schemas.js +2647 -0
- package/dist/lib/types/schemas.js.map +1 -0
- package/dist/lib.d.ts +2 -0
- package/dist/lib.js +1 -0
- package/dist/lib.js.map +1 -0
- package/dist/plugin.d.ts +12 -0
- package/dist/plugin.js +9081 -0
- package/dist/plugin.js.map +1 -0
- package/dist/server/entities/index.d.ts +11 -0
- package/dist/server/entities/index.js +395 -0
- package/dist/server/entities/index.js.map +1 -0
- package/dist/server/entities/invitations.d.ts +241 -0
- package/dist/server/entities/invitations.js +184 -0
- package/dist/server/entities/invitations.js.map +1 -0
- package/dist/server/entities/permissions.d.ts +196 -0
- package/dist/server/entities/permissions.js +49 -0
- package/dist/server/entities/permissions.js.map +1 -0
- package/dist/server/entities/role-permissions.d.ts +107 -0
- package/dist/server/entities/role-permissions.js +115 -0
- package/dist/server/entities/role-permissions.js.map +1 -0
- package/dist/server/entities/roles.d.ts +196 -0
- package/dist/server/entities/roles.js +50 -0
- package/dist/server/entities/roles.js.map +1 -0
- package/dist/server/entities/schema.d.ts +14 -0
- package/dist/server/entities/schema.js +7 -0
- package/dist/server/entities/schema.js.map +1 -0
- package/dist/server/entities/user-permissions.d.ts +163 -0
- package/dist/server/entities/user-permissions.js +193 -0
- package/dist/server/entities/user-permissions.js.map +1 -0
- package/dist/server/entities/user-public-keys.d.ts +227 -0
- package/dist/server/entities/user-public-keys.js +156 -0
- package/dist/server/entities/user-public-keys.js.map +1 -0
- package/dist/server/entities/user-social-accounts.d.ts +189 -0
- package/dist/server/entities/user-social-accounts.js +149 -0
- package/dist/server/entities/user-social-accounts.js.map +1 -0
- package/dist/server/entities/users.d.ts +235 -0
- package/dist/server/entities/users.js +117 -0
- package/dist/server/entities/users.js.map +1 -0
- package/dist/server/entities/verification-codes.d.ts +191 -0
- package/dist/server/entities/verification-codes.js +49 -0
- package/dist/server/entities/verification-codes.js.map +1 -0
- package/dist/server/routes/auth/index.d.ts +10 -0
- package/dist/server/routes/auth/index.js +4458 -0
- package/dist/server/routes/auth/index.js.map +1 -0
- package/dist/server/routes/index.d.ts +6 -0
- package/dist/server/routes/index.js +6582 -0
- package/dist/server/routes/index.js.map +1 -0
- package/dist/server/routes/invitations/index.d.ts +10 -0
- package/dist/server/routes/invitations/index.js +4395 -0
- package/dist/server/routes/invitations/index.js.map +1 -0
- package/dist/server.d.ts +1272 -0
- package/dist/server.js +2274 -0
- package/dist/server.js.map +1 -0
- package/migrations/0000_complex_swordsman.sql +167 -0
- package/migrations/meta/0000_snapshot.json +1397 -0
- package/migrations/meta/_journal.json +13 -0
- package/package.json +59 -24
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,1272 @@
|
|
|
1
|
+
import { User } from './server/entities/users.js';
|
|
2
|
+
import { Role } from './server/entities/roles.js';
|
|
3
|
+
import { Invitation, InvitationWithDetails, InvitationStatus } from './server/entities/invitations.js';
|
|
4
|
+
import { SessionPayload } from './lib/types/api.js';
|
|
5
|
+
import { Context, Next } from 'hono';
|
|
6
|
+
import 'drizzle-orm/pg-core';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @spfn/auth - RBAC Type Definitions
|
|
10
|
+
*
|
|
11
|
+
* Type definitions for role and permission configuration
|
|
12
|
+
*/
|
|
13
|
+
interface RoleConfig {
|
|
14
|
+
name: string;
|
|
15
|
+
displayName: string;
|
|
16
|
+
description?: string;
|
|
17
|
+
priority?: number;
|
|
18
|
+
isSystem?: boolean;
|
|
19
|
+
isBuiltin?: boolean;
|
|
20
|
+
}
|
|
21
|
+
interface PermissionConfig {
|
|
22
|
+
name: string;
|
|
23
|
+
displayName: string;
|
|
24
|
+
description?: string;
|
|
25
|
+
category?: string;
|
|
26
|
+
isSystem?: boolean;
|
|
27
|
+
isBuiltin?: boolean;
|
|
28
|
+
}
|
|
29
|
+
interface AuthInitOptions {
|
|
30
|
+
/**
|
|
31
|
+
* Additional roles to create
|
|
32
|
+
* Built-in roles (user, admin, superadmin) are automatically included
|
|
33
|
+
*/
|
|
34
|
+
roles?: RoleConfig[];
|
|
35
|
+
/**
|
|
36
|
+
* Additional permissions to create
|
|
37
|
+
* Built-in permissions are automatically included
|
|
38
|
+
*/
|
|
39
|
+
permissions?: PermissionConfig[];
|
|
40
|
+
/**
|
|
41
|
+
* Role-Permission mappings
|
|
42
|
+
* Built-in mappings are automatically included
|
|
43
|
+
* You can extend built-in roles or define mappings for custom roles
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```typescript
|
|
47
|
+
* {
|
|
48
|
+
* // Extend built-in admin role
|
|
49
|
+
* admin: ['project:create', 'project:delete'],
|
|
50
|
+
*
|
|
51
|
+
* // Define custom role permissions
|
|
52
|
+
* 'project-manager': ['project:create', 'task:assign'],
|
|
53
|
+
* }
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
rolePermissions?: Record<string, string[]>;
|
|
57
|
+
/**
|
|
58
|
+
* Default role name for new users
|
|
59
|
+
* Must be a valid role name that exists after initialization
|
|
60
|
+
* @default 'user'
|
|
61
|
+
*/
|
|
62
|
+
defaultRole?: string;
|
|
63
|
+
/**
|
|
64
|
+
* Default session TTL (Time To Live)
|
|
65
|
+
*
|
|
66
|
+
* Supports:
|
|
67
|
+
* - Number: seconds (e.g., 2592000)
|
|
68
|
+
* - String: duration format ('30d', '12h', '45m', '3600s')
|
|
69
|
+
*
|
|
70
|
+
* Can be overridden at runtime with `remember` parameter.
|
|
71
|
+
*
|
|
72
|
+
* @default '7d' (7 days)
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* ```typescript
|
|
76
|
+
* {
|
|
77
|
+
* sessionTtl: '30d', // 30 days
|
|
78
|
+
* }
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
sessionTtl?: string | number;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* @spfn/auth - Built-in Roles and Permissions
|
|
86
|
+
*
|
|
87
|
+
* Core roles and permissions required by the auth package
|
|
88
|
+
* These cannot be deleted and are automatically created on initialization
|
|
89
|
+
*/
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Built-in roles (required by package)
|
|
93
|
+
* These roles are always created and cannot be deleted
|
|
94
|
+
*/
|
|
95
|
+
declare const BUILTIN_ROLES: Record<string, RoleConfig>;
|
|
96
|
+
/**
|
|
97
|
+
* Built-in permissions (required by package)
|
|
98
|
+
* These permissions are always created and cannot be deleted
|
|
99
|
+
*/
|
|
100
|
+
declare const BUILTIN_PERMISSIONS: Record<string, PermissionConfig>;
|
|
101
|
+
/**
|
|
102
|
+
* Built-in role-permission mappings
|
|
103
|
+
* Defines default permissions for each built-in role
|
|
104
|
+
*/
|
|
105
|
+
declare const BUILTIN_ROLE_PERMISSIONS: Record<string, string[]>;
|
|
106
|
+
type BuiltinRoleName = keyof typeof BUILTIN_ROLE_PERMISSIONS;
|
|
107
|
+
type BuiltinPermissionName = typeof BUILTIN_PERMISSIONS[keyof typeof BUILTIN_PERMISSIONS]['name'];
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* @spfn/auth - Auth Service
|
|
111
|
+
*
|
|
112
|
+
* Core authentication logic: registration, login, logout, password management
|
|
113
|
+
*/
|
|
114
|
+
interface CheckAccountExistsParams {
|
|
115
|
+
email?: string;
|
|
116
|
+
phone?: string;
|
|
117
|
+
}
|
|
118
|
+
interface CheckAccountExistsResult {
|
|
119
|
+
exists: boolean;
|
|
120
|
+
identifier: string;
|
|
121
|
+
identifierType: 'email' | 'phone';
|
|
122
|
+
}
|
|
123
|
+
interface RegisterParams {
|
|
124
|
+
email?: string;
|
|
125
|
+
phone?: string;
|
|
126
|
+
verificationToken: string;
|
|
127
|
+
password: string;
|
|
128
|
+
publicKey: string;
|
|
129
|
+
keyId: string;
|
|
130
|
+
fingerprint: string;
|
|
131
|
+
algorithm?: 'ES256' | 'RS256';
|
|
132
|
+
}
|
|
133
|
+
interface RegisterResult {
|
|
134
|
+
userId: string;
|
|
135
|
+
email?: string;
|
|
136
|
+
phone?: string;
|
|
137
|
+
}
|
|
138
|
+
interface LoginParams {
|
|
139
|
+
email?: string;
|
|
140
|
+
phone?: string;
|
|
141
|
+
password: string;
|
|
142
|
+
publicKey: string;
|
|
143
|
+
keyId: string;
|
|
144
|
+
fingerprint: string;
|
|
145
|
+
oldKeyId?: string;
|
|
146
|
+
algorithm?: 'ES256' | 'RS256';
|
|
147
|
+
}
|
|
148
|
+
interface LoginResult {
|
|
149
|
+
userId: string;
|
|
150
|
+
email?: string;
|
|
151
|
+
phone?: string;
|
|
152
|
+
passwordChangeRequired: boolean;
|
|
153
|
+
}
|
|
154
|
+
interface LogoutParams {
|
|
155
|
+
userId: number;
|
|
156
|
+
keyId: string;
|
|
157
|
+
}
|
|
158
|
+
interface ChangePasswordParams {
|
|
159
|
+
userId: number;
|
|
160
|
+
currentPassword: string;
|
|
161
|
+
newPassword: string;
|
|
162
|
+
passwordHash?: string;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Check if an account exists by email or phone
|
|
166
|
+
*/
|
|
167
|
+
declare function checkAccountExistsService(params: CheckAccountExistsParams): Promise<CheckAccountExistsResult>;
|
|
168
|
+
/**
|
|
169
|
+
* Register a new user account
|
|
170
|
+
*/
|
|
171
|
+
declare function registerService(params: RegisterParams): Promise<RegisterResult>;
|
|
172
|
+
/**
|
|
173
|
+
* Authenticate user and create session
|
|
174
|
+
*/
|
|
175
|
+
declare function loginService(params: LoginParams): Promise<LoginResult>;
|
|
176
|
+
/**
|
|
177
|
+
* Logout user (revoke current key)
|
|
178
|
+
*/
|
|
179
|
+
declare function logoutService(params: LogoutParams): Promise<void>;
|
|
180
|
+
/**
|
|
181
|
+
* Change user password
|
|
182
|
+
*/
|
|
183
|
+
declare function changePasswordService(params: ChangePasswordParams): Promise<void>;
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* @spfn/auth - Verification Service
|
|
187
|
+
*
|
|
188
|
+
* Handles OTP code generation, validation, and delivery
|
|
189
|
+
*/
|
|
190
|
+
interface SendVerificationCodeParams {
|
|
191
|
+
target: string;
|
|
192
|
+
targetType: 'email' | 'phone';
|
|
193
|
+
purpose: 'registration' | 'login' | 'password_reset';
|
|
194
|
+
}
|
|
195
|
+
interface SendVerificationCodeResult {
|
|
196
|
+
success: boolean;
|
|
197
|
+
expiresAt: string;
|
|
198
|
+
}
|
|
199
|
+
interface VerifyCodeParams {
|
|
200
|
+
target: string;
|
|
201
|
+
targetType: 'email' | 'phone';
|
|
202
|
+
code: string;
|
|
203
|
+
purpose: 'registration' | 'login' | 'password_reset';
|
|
204
|
+
}
|
|
205
|
+
interface VerifyCodeResult {
|
|
206
|
+
valid: boolean;
|
|
207
|
+
verificationToken: string;
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Send verification code via email or SMS
|
|
211
|
+
*/
|
|
212
|
+
declare function sendVerificationCodeService(params: SendVerificationCodeParams): Promise<SendVerificationCodeResult>;
|
|
213
|
+
/**
|
|
214
|
+
* Verify OTP code and return verification token
|
|
215
|
+
*/
|
|
216
|
+
declare function verifyCodeService(params: VerifyCodeParams): Promise<VerifyCodeResult>;
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* @spfn/auth - Key Service
|
|
220
|
+
*
|
|
221
|
+
* Handles public key registration, rotation, and revocation
|
|
222
|
+
*/
|
|
223
|
+
interface RegisterPublicKeyParams {
|
|
224
|
+
userId: number;
|
|
225
|
+
keyId: string;
|
|
226
|
+
publicKey: string;
|
|
227
|
+
fingerprint: string;
|
|
228
|
+
algorithm?: 'ES256' | 'RS256';
|
|
229
|
+
}
|
|
230
|
+
interface RotateKeyParams {
|
|
231
|
+
userId: number;
|
|
232
|
+
oldKeyId: string;
|
|
233
|
+
newKeyId: string;
|
|
234
|
+
newPublicKey: string;
|
|
235
|
+
fingerprint: string;
|
|
236
|
+
algorithm?: 'ES256' | 'RS256';
|
|
237
|
+
}
|
|
238
|
+
interface RotateKeyResult {
|
|
239
|
+
success: boolean;
|
|
240
|
+
keyId: string;
|
|
241
|
+
}
|
|
242
|
+
interface RevokeKeyParams {
|
|
243
|
+
userId: number;
|
|
244
|
+
keyId: string;
|
|
245
|
+
reason: string;
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Register a new public key for a user
|
|
249
|
+
*/
|
|
250
|
+
declare function registerPublicKeyService(params: RegisterPublicKeyParams): Promise<void>;
|
|
251
|
+
/**
|
|
252
|
+
* Rotate user's public key (revoke old, register new)
|
|
253
|
+
*/
|
|
254
|
+
declare function rotateKeyService(params: RotateKeyParams): Promise<RotateKeyResult>;
|
|
255
|
+
/**
|
|
256
|
+
* Revoke a user's public key
|
|
257
|
+
*/
|
|
258
|
+
declare function revokeKeyService(params: RevokeKeyParams): Promise<void>;
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* @spfn/auth - User Service
|
|
262
|
+
*
|
|
263
|
+
* Handles user CRUD operations
|
|
264
|
+
*/
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Get user by ID
|
|
268
|
+
*/
|
|
269
|
+
declare function getUserByIdService(userId: number): Promise<User | null>;
|
|
270
|
+
/**
|
|
271
|
+
* Get user by email
|
|
272
|
+
*/
|
|
273
|
+
declare function getUserByEmailService(email: string): Promise<User | null>;
|
|
274
|
+
/**
|
|
275
|
+
* Get user by phone
|
|
276
|
+
*/
|
|
277
|
+
declare function getUserByPhoneService(phone: string): Promise<User | null>;
|
|
278
|
+
/**
|
|
279
|
+
* Update user's last login timestamp
|
|
280
|
+
*/
|
|
281
|
+
declare function updateLastLoginService(userId: number): Promise<void>;
|
|
282
|
+
/**
|
|
283
|
+
* Update user data
|
|
284
|
+
*/
|
|
285
|
+
declare function updateUserService(userId: number, updates: Partial<Omit<User, 'id' | 'createdAt'>>): Promise<void>;
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* @spfn/auth - Me Service
|
|
289
|
+
*
|
|
290
|
+
* Service for retrieving current user information
|
|
291
|
+
*/
|
|
292
|
+
interface GetMeResult {
|
|
293
|
+
userId: string;
|
|
294
|
+
email?: string;
|
|
295
|
+
phone?: string;
|
|
296
|
+
role: {
|
|
297
|
+
id: number;
|
|
298
|
+
name: string;
|
|
299
|
+
displayName: string;
|
|
300
|
+
priority: number;
|
|
301
|
+
};
|
|
302
|
+
permissions: Array<{
|
|
303
|
+
id: number;
|
|
304
|
+
name: string;
|
|
305
|
+
displayName: string;
|
|
306
|
+
category?: string;
|
|
307
|
+
}>;
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Get current user information including role and permissions
|
|
311
|
+
*
|
|
312
|
+
* @param userId - User ID (string, number, or bigint)
|
|
313
|
+
* @returns User info with role and permissions
|
|
314
|
+
*
|
|
315
|
+
* @example
|
|
316
|
+
* ```typescript
|
|
317
|
+
* const userInfo = await getMeService('123');
|
|
318
|
+
* console.log(userInfo.role.name); // 'admin'
|
|
319
|
+
* console.log(userInfo.permissions.length); // 15
|
|
320
|
+
* ```
|
|
321
|
+
*/
|
|
322
|
+
declare function getMeService(userId: string | number | bigint): Promise<GetMeResult>;
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* @spfn/auth - RBAC Initialization Service
|
|
326
|
+
*
|
|
327
|
+
* Initialize roles, permissions, and their mappings
|
|
328
|
+
*/
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Initialize auth package with RBAC system
|
|
332
|
+
*
|
|
333
|
+
* Creates built-in roles, permissions, and custom configurations
|
|
334
|
+
*
|
|
335
|
+
* @param options - Initialization options
|
|
336
|
+
*
|
|
337
|
+
* @example
|
|
338
|
+
* ```typescript
|
|
339
|
+
* // Minimal - only built-in roles (user, admin, superadmin)
|
|
340
|
+
* await initializeAuth();
|
|
341
|
+
*
|
|
342
|
+
* // Custom roles and permissions
|
|
343
|
+
* await initializeAuth({
|
|
344
|
+
* roles: [
|
|
345
|
+
* { name: 'project-manager', displayName: 'Project Manager', priority: 50 },
|
|
346
|
+
* { name: 'developer', displayName: 'Developer', priority: 30 },
|
|
347
|
+
* ],
|
|
348
|
+
* permissions: [
|
|
349
|
+
* { name: 'project:create', displayName: 'Create Project', category: 'project' },
|
|
350
|
+
* { name: 'task:assign', displayName: 'Assign Task', category: 'task' },
|
|
351
|
+
* ],
|
|
352
|
+
* rolePermissions: {
|
|
353
|
+
* 'project-manager': ['project:create', 'task:assign'],
|
|
354
|
+
* 'developer': ['task:complete'],
|
|
355
|
+
* },
|
|
356
|
+
* });
|
|
357
|
+
* ```
|
|
358
|
+
*/
|
|
359
|
+
declare function initializeAuth(options?: AuthInitOptions): Promise<void>;
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* @spfn/auth - Permission Service
|
|
363
|
+
*
|
|
364
|
+
* Permission checking and validation logic
|
|
365
|
+
*/
|
|
366
|
+
/**
|
|
367
|
+
* Get all permissions for a user
|
|
368
|
+
*
|
|
369
|
+
* Combines role-based permissions with user-specific overrides
|
|
370
|
+
* Handles expiration of temporary permissions
|
|
371
|
+
*
|
|
372
|
+
* @param userId - User ID (string, number, or bigint)
|
|
373
|
+
* @returns Array of permission names
|
|
374
|
+
*
|
|
375
|
+
* @example
|
|
376
|
+
* ```typescript
|
|
377
|
+
* const perms = await getUserPermissions('123');
|
|
378
|
+
* // ['auth:self:manage', 'user:read', 'post:create']
|
|
379
|
+
* ```
|
|
380
|
+
*/
|
|
381
|
+
declare function getUserPermissions(userId: string | number | bigint): Promise<string[]>;
|
|
382
|
+
/**
|
|
383
|
+
* Check if user has a specific permission
|
|
384
|
+
*
|
|
385
|
+
* @param userId - User ID
|
|
386
|
+
* @param permissionName - Permission name (e.g., 'user:delete')
|
|
387
|
+
* @returns true if user has permission
|
|
388
|
+
*
|
|
389
|
+
* @example
|
|
390
|
+
* ```typescript
|
|
391
|
+
* if (await hasPermission('123', 'user:delete')) {
|
|
392
|
+
* // User can delete users
|
|
393
|
+
* }
|
|
394
|
+
* ```
|
|
395
|
+
*/
|
|
396
|
+
declare function hasPermission(userId: string | number | bigint, permissionName: string): Promise<boolean>;
|
|
397
|
+
/**
|
|
398
|
+
* Check if user has any of the specified permissions
|
|
399
|
+
*
|
|
400
|
+
* @param userId - User ID
|
|
401
|
+
* @param permissionNames - Array of permission names
|
|
402
|
+
* @returns true if user has at least one permission
|
|
403
|
+
*
|
|
404
|
+
* @example
|
|
405
|
+
* ```typescript
|
|
406
|
+
* if (await hasAnyPermission('123', ['post:read', 'admin:access'])) {
|
|
407
|
+
* // User can access content
|
|
408
|
+
* }
|
|
409
|
+
* ```
|
|
410
|
+
*/
|
|
411
|
+
declare function hasAnyPermission(userId: string | number | bigint, permissionNames: string[]): Promise<boolean>;
|
|
412
|
+
/**
|
|
413
|
+
* Check if user has all of the specified permissions
|
|
414
|
+
*
|
|
415
|
+
* @param userId - User ID
|
|
416
|
+
* @param permissionNames - Array of permission names
|
|
417
|
+
* @returns true if user has all permissions
|
|
418
|
+
*
|
|
419
|
+
* @example
|
|
420
|
+
* ```typescript
|
|
421
|
+
* if (await hasAllPermissions('123', ['post:write', 'post:publish'])) {
|
|
422
|
+
* // User can write AND publish
|
|
423
|
+
* }
|
|
424
|
+
* ```
|
|
425
|
+
*/
|
|
426
|
+
declare function hasAllPermissions(userId: string | number | bigint, permissionNames: string[]): Promise<boolean>;
|
|
427
|
+
/**
|
|
428
|
+
* Check if user has a specific role
|
|
429
|
+
*
|
|
430
|
+
* @param userId - User ID
|
|
431
|
+
* @param roleName - Role name (e.g., 'admin', 'superadmin')
|
|
432
|
+
* @returns true if user has role
|
|
433
|
+
*
|
|
434
|
+
* @example
|
|
435
|
+
* ```typescript
|
|
436
|
+
* if (await hasRole('123', 'admin')) {
|
|
437
|
+
* // User is admin
|
|
438
|
+
* }
|
|
439
|
+
* ```
|
|
440
|
+
*/
|
|
441
|
+
declare function hasRole(userId: string | number | bigint, roleName: string): Promise<boolean>;
|
|
442
|
+
/**
|
|
443
|
+
* Check if user has any of the specified roles
|
|
444
|
+
*
|
|
445
|
+
* @param userId - User ID
|
|
446
|
+
* @param roleNames - Array of role names
|
|
447
|
+
* @returns true if user has at least one role
|
|
448
|
+
*/
|
|
449
|
+
declare function hasAnyRole(userId: string | number | bigint, roleNames: string[]): Promise<boolean>;
|
|
450
|
+
|
|
451
|
+
/**
|
|
452
|
+
* @spfn/auth - Role Service
|
|
453
|
+
*
|
|
454
|
+
* Role management functions for runtime role creation and modification
|
|
455
|
+
*/
|
|
456
|
+
|
|
457
|
+
/**
|
|
458
|
+
* Create a new custom role
|
|
459
|
+
*
|
|
460
|
+
* @param data - Role configuration
|
|
461
|
+
* @returns Created role
|
|
462
|
+
* @throws Error if role name already exists
|
|
463
|
+
*
|
|
464
|
+
* @example
|
|
465
|
+
* ```typescript
|
|
466
|
+
* const role = await createRole({
|
|
467
|
+
* name: 'content-creator',
|
|
468
|
+
* displayName: 'Content Creator',
|
|
469
|
+
* description: 'Can create and publish content',
|
|
470
|
+
* priority: 20,
|
|
471
|
+
* permissionIds: [1n, 2n, 3n],
|
|
472
|
+
* });
|
|
473
|
+
* ```
|
|
474
|
+
*/
|
|
475
|
+
declare function createRole(data: {
|
|
476
|
+
name: string;
|
|
477
|
+
displayName: string;
|
|
478
|
+
description?: string;
|
|
479
|
+
priority?: number;
|
|
480
|
+
permissionIds?: number[];
|
|
481
|
+
}): Promise<Role>;
|
|
482
|
+
/**
|
|
483
|
+
* Update an existing role
|
|
484
|
+
*
|
|
485
|
+
* @param roleId - Role ID
|
|
486
|
+
* @param data - Update data
|
|
487
|
+
* @returns Updated role
|
|
488
|
+
* @throws Error if role is built-in (cannot modify)
|
|
489
|
+
*
|
|
490
|
+
* @example
|
|
491
|
+
* ```typescript
|
|
492
|
+
* await updateRole(1n, {
|
|
493
|
+
* displayName: 'Senior Content Creator',
|
|
494
|
+
* priority: 25,
|
|
495
|
+
* });
|
|
496
|
+
* ```
|
|
497
|
+
*/
|
|
498
|
+
declare function updateRole(roleId: number, data: {
|
|
499
|
+
displayName?: string;
|
|
500
|
+
description?: string;
|
|
501
|
+
priority?: number;
|
|
502
|
+
isActive?: boolean;
|
|
503
|
+
}): Promise<Role>;
|
|
504
|
+
/**
|
|
505
|
+
* Delete a role
|
|
506
|
+
*
|
|
507
|
+
* @param roleId - Role ID
|
|
508
|
+
* @throws Error if role is built-in or system role
|
|
509
|
+
*
|
|
510
|
+
* @example
|
|
511
|
+
* ```typescript
|
|
512
|
+
* await deleteRole(5n); // Delete custom role
|
|
513
|
+
* ```
|
|
514
|
+
*/
|
|
515
|
+
declare function deleteRole(roleId: number): Promise<void>;
|
|
516
|
+
/**
|
|
517
|
+
* Add permission to role
|
|
518
|
+
*
|
|
519
|
+
* @param roleId - Role ID
|
|
520
|
+
* @param permissionId - Permission ID
|
|
521
|
+
*
|
|
522
|
+
* @example
|
|
523
|
+
* ```typescript
|
|
524
|
+
* await addPermissionToRole(1n, 5n);
|
|
525
|
+
* ```
|
|
526
|
+
*/
|
|
527
|
+
declare function addPermissionToRole(roleId: number, permissionId: number): Promise<void>;
|
|
528
|
+
/**
|
|
529
|
+
* Remove permission from role
|
|
530
|
+
*
|
|
531
|
+
* @param roleId - Role ID
|
|
532
|
+
* @param permissionId - Permission ID
|
|
533
|
+
*
|
|
534
|
+
* @example
|
|
535
|
+
* ```typescript
|
|
536
|
+
* await removePermissionFromRole(1n, 5n);
|
|
537
|
+
* ```
|
|
538
|
+
*/
|
|
539
|
+
declare function removePermissionFromRole(roleId: number, permissionId: number): Promise<void>;
|
|
540
|
+
/**
|
|
541
|
+
* Set permissions for a role (replaces all existing permissions)
|
|
542
|
+
*
|
|
543
|
+
* @param roleId - Role ID
|
|
544
|
+
* @param permissionIds - Array of permission IDs
|
|
545
|
+
*
|
|
546
|
+
* @example
|
|
547
|
+
* ```typescript
|
|
548
|
+
* await setRolePermissions(1n, [1n, 2n, 3n]);
|
|
549
|
+
* ```
|
|
550
|
+
*/
|
|
551
|
+
declare function setRolePermissions(roleId: number, permissionIds: number[]): Promise<void>;
|
|
552
|
+
/**
|
|
553
|
+
* Get all roles
|
|
554
|
+
*
|
|
555
|
+
* @param includeInactive - Include inactive roles
|
|
556
|
+
* @returns Array of roles
|
|
557
|
+
*
|
|
558
|
+
* @example
|
|
559
|
+
* ```typescript
|
|
560
|
+
* const roles = await getAllRoles();
|
|
561
|
+
* ```
|
|
562
|
+
*/
|
|
563
|
+
declare function getAllRoles(includeInactive?: boolean): Promise<Role[]>;
|
|
564
|
+
/**
|
|
565
|
+
* Get role by name
|
|
566
|
+
*
|
|
567
|
+
* @param name - Role name
|
|
568
|
+
* @returns Role or null
|
|
569
|
+
*
|
|
570
|
+
* @example
|
|
571
|
+
* ```typescript
|
|
572
|
+
* const role = await getRoleByName('admin');
|
|
573
|
+
* ```
|
|
574
|
+
*/
|
|
575
|
+
declare function getRoleByName(name: string): Promise<Role | null>;
|
|
576
|
+
/**
|
|
577
|
+
* Get role permissions
|
|
578
|
+
*
|
|
579
|
+
* @param roleId - Role ID
|
|
580
|
+
* @returns Array of permission names
|
|
581
|
+
*
|
|
582
|
+
* @example
|
|
583
|
+
* ```typescript
|
|
584
|
+
* const perms = await getRolePermissions(1n);
|
|
585
|
+
* // ['user:read', 'user:write']
|
|
586
|
+
* ```
|
|
587
|
+
*/
|
|
588
|
+
declare function getRolePermissions(roleId: number): Promise<string[]>;
|
|
589
|
+
|
|
590
|
+
/**
|
|
591
|
+
* @spfn/auth - Invitation Service
|
|
592
|
+
*
|
|
593
|
+
* User invitation management for invite-only registration
|
|
594
|
+
*/
|
|
595
|
+
|
|
596
|
+
/**
|
|
597
|
+
* Create a new invitation
|
|
598
|
+
*
|
|
599
|
+
* @param params - Invitation parameters
|
|
600
|
+
* @returns Created invitation
|
|
601
|
+
* @throws Error if validation fails
|
|
602
|
+
*
|
|
603
|
+
* @example
|
|
604
|
+
* ```typescript
|
|
605
|
+
* const invitation = await createInvitation({
|
|
606
|
+
* email: 'newuser@example.com',
|
|
607
|
+
* roleId: 2n,
|
|
608
|
+
* invitedBy: 1n,
|
|
609
|
+
* expiresInDays: 7,
|
|
610
|
+
* metadata: { message: 'Welcome!' }
|
|
611
|
+
* });
|
|
612
|
+
* ```
|
|
613
|
+
*/
|
|
614
|
+
declare function createInvitation(params: {
|
|
615
|
+
email: string;
|
|
616
|
+
roleId: number;
|
|
617
|
+
invitedBy: number;
|
|
618
|
+
expiresInDays?: number;
|
|
619
|
+
metadata?: Record<string, any>;
|
|
620
|
+
}): Promise<Invitation>;
|
|
621
|
+
/**
|
|
622
|
+
* Get invitation by token
|
|
623
|
+
*
|
|
624
|
+
* @param token - Invitation token (UUID)
|
|
625
|
+
* @returns Invitation or null if not found
|
|
626
|
+
*/
|
|
627
|
+
declare function getInvitationByToken(token: string): Promise<Invitation | null>;
|
|
628
|
+
/**
|
|
629
|
+
* Get invitation with role and inviter details
|
|
630
|
+
*
|
|
631
|
+
* @param token - Invitation token
|
|
632
|
+
* @returns Invitation with joined data or null
|
|
633
|
+
*/
|
|
634
|
+
declare function getInvitationWithDetails(token: string): Promise<InvitationWithDetails | null>;
|
|
635
|
+
/**
|
|
636
|
+
* Validate invitation
|
|
637
|
+
*
|
|
638
|
+
* Checks if invitation is valid for acceptance
|
|
639
|
+
*
|
|
640
|
+
* @param token - Invitation token
|
|
641
|
+
* @returns Validation result
|
|
642
|
+
*/
|
|
643
|
+
declare function validateInvitation(token: string): Promise<{
|
|
644
|
+
valid: boolean;
|
|
645
|
+
invitation?: Invitation;
|
|
646
|
+
error?: string;
|
|
647
|
+
}>;
|
|
648
|
+
/**
|
|
649
|
+
* Accept invitation and create user account
|
|
650
|
+
*
|
|
651
|
+
* @param params - Acceptance parameters
|
|
652
|
+
* @returns Created user info
|
|
653
|
+
* @throws Error if invitation is invalid or user creation fails
|
|
654
|
+
*
|
|
655
|
+
* @example
|
|
656
|
+
* ```typescript
|
|
657
|
+
* const user = await acceptInvitation({
|
|
658
|
+
* token: 'uuid-v4',
|
|
659
|
+
* password: 'SecurePass123!',
|
|
660
|
+
* publicKey: 'base64-der...',
|
|
661
|
+
* keyId: 'uuid-v4',
|
|
662
|
+
* fingerprint: 'sha256-hex',
|
|
663
|
+
* algorithm: 'ES256'
|
|
664
|
+
* });
|
|
665
|
+
* ```
|
|
666
|
+
*/
|
|
667
|
+
declare function acceptInvitation(params: {
|
|
668
|
+
token: string;
|
|
669
|
+
password: string;
|
|
670
|
+
publicKey: string;
|
|
671
|
+
keyId: string;
|
|
672
|
+
fingerprint: string;
|
|
673
|
+
algorithm: 'ES256' | 'RS256';
|
|
674
|
+
}): Promise<{
|
|
675
|
+
userId: number;
|
|
676
|
+
email: string;
|
|
677
|
+
role: string;
|
|
678
|
+
}>;
|
|
679
|
+
/**
|
|
680
|
+
* List invitations with filtering and pagination
|
|
681
|
+
*
|
|
682
|
+
* @param params - Query parameters
|
|
683
|
+
* @returns Paginated invitations
|
|
684
|
+
*
|
|
685
|
+
* @example
|
|
686
|
+
* ```typescript
|
|
687
|
+
* const result = await listInvitations({
|
|
688
|
+
* status: 'pending',
|
|
689
|
+
* invitedBy: 1n,
|
|
690
|
+
* page: 1,
|
|
691
|
+
* limit: 20
|
|
692
|
+
* });
|
|
693
|
+
* ```
|
|
694
|
+
*/
|
|
695
|
+
declare function listInvitations(params: {
|
|
696
|
+
status?: InvitationStatus;
|
|
697
|
+
invitedBy?: number;
|
|
698
|
+
page?: number;
|
|
699
|
+
limit?: number;
|
|
700
|
+
}): Promise<{
|
|
701
|
+
invitations: InvitationWithDetails[];
|
|
702
|
+
total: number;
|
|
703
|
+
page: number;
|
|
704
|
+
limit: number;
|
|
705
|
+
totalPages: number;
|
|
706
|
+
}>;
|
|
707
|
+
/**
|
|
708
|
+
* Cancel invitation
|
|
709
|
+
*
|
|
710
|
+
* Only pending invitations can be cancelled
|
|
711
|
+
*
|
|
712
|
+
* @param id - Invitation ID
|
|
713
|
+
* @param cancelledBy - User ID who cancelled
|
|
714
|
+
* @param reason - Optional cancellation reason
|
|
715
|
+
* @throws Error if invitation cannot be cancelled
|
|
716
|
+
*/
|
|
717
|
+
declare function cancelInvitation(id: number, cancelledBy: number, reason?: string): Promise<void>;
|
|
718
|
+
/**
|
|
719
|
+
* Delete invitation
|
|
720
|
+
*
|
|
721
|
+
* Permanently removes invitation record
|
|
722
|
+
* Typically only for superadmin cleanup
|
|
723
|
+
*
|
|
724
|
+
* @param id - Invitation ID
|
|
725
|
+
*/
|
|
726
|
+
declare function deleteInvitation(id: number): Promise<void>;
|
|
727
|
+
/**
|
|
728
|
+
* Expire old invitations (cron job)
|
|
729
|
+
*
|
|
730
|
+
* Updates status of expired pending invitations
|
|
731
|
+
*
|
|
732
|
+
* @returns Number of invitations expired
|
|
733
|
+
*/
|
|
734
|
+
declare function expireOldInvitations(): Promise<number>;
|
|
735
|
+
/**
|
|
736
|
+
* Resend invitation email
|
|
737
|
+
*
|
|
738
|
+
* Extends expiration and triggers email resend
|
|
739
|
+
*
|
|
740
|
+
* @param id - Invitation ID
|
|
741
|
+
* @param expiresInDays - New expiration period (default: 7)
|
|
742
|
+
* @returns Updated invitation
|
|
743
|
+
* @throws Error if invitation cannot be resent
|
|
744
|
+
*/
|
|
745
|
+
declare function resendInvitation(id: number, expiresInDays?: number): Promise<Invitation>;
|
|
746
|
+
|
|
747
|
+
/**
|
|
748
|
+
* @spfn/auth - Password Helpers
|
|
749
|
+
*
|
|
750
|
+
* Password hashing and verification using bcrypt
|
|
751
|
+
*
|
|
752
|
+
* Security:
|
|
753
|
+
* - Adaptive hashing (configurable rounds)
|
|
754
|
+
* - Automatic salt generation (per-password)
|
|
755
|
+
* - Constant-time comparison (timing attack protection)
|
|
756
|
+
* - Rainbow table protection
|
|
757
|
+
*/
|
|
758
|
+
/**
|
|
759
|
+
* Hash a plain text password using bcrypt
|
|
760
|
+
*
|
|
761
|
+
* Algorithm:
|
|
762
|
+
* 1. Generate random salt (128-bit)
|
|
763
|
+
* 2. Apply bcrypt key derivation (2^rounds iterations)
|
|
764
|
+
* 3. Return $2b$rounds$[salt][hash] (60 chars)
|
|
765
|
+
*
|
|
766
|
+
* @param password - Plain text password to hash
|
|
767
|
+
* @returns Bcrypt hash string (includes salt)
|
|
768
|
+
* @throws Error if password is empty or invalid
|
|
769
|
+
*
|
|
770
|
+
* @example
|
|
771
|
+
* ```typescript
|
|
772
|
+
* const hash = await hashPassword('mySecurePassword123');
|
|
773
|
+
* // Returns: "$2b$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy"
|
|
774
|
+
* ```
|
|
775
|
+
*/
|
|
776
|
+
declare function hashPassword(password: string): Promise<string>;
|
|
777
|
+
/**
|
|
778
|
+
* Verify a password against a bcrypt hash
|
|
779
|
+
*
|
|
780
|
+
* Uses constant-time comparison to prevent timing attacks
|
|
781
|
+
* Automatically extracts salt from hash for verification
|
|
782
|
+
*
|
|
783
|
+
* @param password - Plain text password to verify
|
|
784
|
+
* @param hash - Bcrypt hash string (from hashPassword)
|
|
785
|
+
* @returns True if password matches hash
|
|
786
|
+
* @throws Error if inputs are invalid
|
|
787
|
+
*
|
|
788
|
+
* @example
|
|
789
|
+
* ```typescript
|
|
790
|
+
* const isValid = await verifyPassword(
|
|
791
|
+
* 'mySecurePassword123',
|
|
792
|
+
* '$2b$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy'
|
|
793
|
+
* );
|
|
794
|
+
* // Returns: true
|
|
795
|
+
* ```
|
|
796
|
+
*/
|
|
797
|
+
declare function verifyPassword(password: string, hash: string): Promise<boolean>;
|
|
798
|
+
/**
|
|
799
|
+
* Validate password strength
|
|
800
|
+
*
|
|
801
|
+
* Requirements:
|
|
802
|
+
* - Minimum 8 characters
|
|
803
|
+
* - At least one uppercase letter
|
|
804
|
+
* - At least one lowercase letter
|
|
805
|
+
* - At least one number
|
|
806
|
+
* - At least one special character
|
|
807
|
+
*
|
|
808
|
+
* @param password - Password to validate
|
|
809
|
+
* @returns Validation result with error messages
|
|
810
|
+
*
|
|
811
|
+
* @example
|
|
812
|
+
* ```typescript
|
|
813
|
+
* const result = validatePasswordStrength('weak');
|
|
814
|
+
* // Returns: { valid: false, errors: ['Too short', 'Missing uppercase', ...] }
|
|
815
|
+
*
|
|
816
|
+
* const result = validatePasswordStrength('SecurePass123!');
|
|
817
|
+
* // Returns: { valid: true, errors: [] }
|
|
818
|
+
* ```
|
|
819
|
+
*/
|
|
820
|
+
declare function validatePasswordStrength(password: string): {
|
|
821
|
+
valid: boolean;
|
|
822
|
+
errors: string[];
|
|
823
|
+
};
|
|
824
|
+
|
|
825
|
+
/**
|
|
826
|
+
* @spfn/auth - JWT Helpers
|
|
827
|
+
*
|
|
828
|
+
* JWT token generation and verification
|
|
829
|
+
* Supports both server-signed (legacy) and client-signed (asymmetric) tokens
|
|
830
|
+
*
|
|
831
|
+
* Architecture:
|
|
832
|
+
* - Legacy: Server signs/verifies with SPFN_AUTH_JWT_SECRET (symmetric HMAC)
|
|
833
|
+
* - New: Client signs with privateKey, server verifies with publicKey (asymmetric)
|
|
834
|
+
*/
|
|
835
|
+
|
|
836
|
+
interface TokenPayload extends SessionPayload {
|
|
837
|
+
exp?: number;
|
|
838
|
+
iat?: number;
|
|
839
|
+
iss?: string;
|
|
840
|
+
keyId?: string;
|
|
841
|
+
timestamp?: number;
|
|
842
|
+
[key: string]: any;
|
|
843
|
+
}
|
|
844
|
+
/**
|
|
845
|
+
* Generate a JWT token (legacy server-signed)
|
|
846
|
+
*
|
|
847
|
+
* @deprecated Use client-side signing with private keys instead
|
|
848
|
+
* This method uses symmetric HMAC which requires sharing the secret
|
|
849
|
+
*
|
|
850
|
+
* @param payload - Token payload
|
|
851
|
+
* @returns JWT token string
|
|
852
|
+
*/
|
|
853
|
+
declare function generateToken(payload: SessionPayload): string;
|
|
854
|
+
/**
|
|
855
|
+
* Verify and decode a JWT token (legacy server-signed)
|
|
856
|
+
*
|
|
857
|
+
* @deprecated Use verifyClientToken for client-signed tokens
|
|
858
|
+
* This method uses symmetric HMAC verification
|
|
859
|
+
*
|
|
860
|
+
* @param token - JWT token to verify
|
|
861
|
+
* @returns Decoded payload
|
|
862
|
+
* @throws Error if verification fails
|
|
863
|
+
*/
|
|
864
|
+
declare function verifyToken(token: string): TokenPayload;
|
|
865
|
+
/**
|
|
866
|
+
* Verify client-signed JWT token with public key (DER format)
|
|
867
|
+
*
|
|
868
|
+
* Flow:
|
|
869
|
+
* 1. Decode Base64 DER to Buffer
|
|
870
|
+
* 2. Create KeyObject from DER
|
|
871
|
+
* 3. Verify JWT signature with public key
|
|
872
|
+
* 4. Validate issuer claim
|
|
873
|
+
*
|
|
874
|
+
* @param token - JWT token signed by client's private key
|
|
875
|
+
* @param publicKeyB64 - Base64 encoded DER public key (SPKI format)
|
|
876
|
+
* @param algorithm - Algorithm used for signing (ES256 or RS256)
|
|
877
|
+
* @returns Decoded token payload
|
|
878
|
+
* @throws Error if verification fails
|
|
879
|
+
*
|
|
880
|
+
* @example
|
|
881
|
+
* ```typescript
|
|
882
|
+
* const payload = verifyClientToken(
|
|
883
|
+
* token,
|
|
884
|
+
* 'MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE...',
|
|
885
|
+
* 'ES256'
|
|
886
|
+
* );
|
|
887
|
+
* ```
|
|
888
|
+
*/
|
|
889
|
+
declare function verifyClientToken(token: string, publicKeyB64: string, algorithm: 'ES256' | 'RS256'): TokenPayload;
|
|
890
|
+
/**
|
|
891
|
+
* Decode a JWT token without verification (for debugging)
|
|
892
|
+
*
|
|
893
|
+
* WARNING: Does not verify signature! Only use for debugging/logging.
|
|
894
|
+
* Never trust decoded data without verification.
|
|
895
|
+
*
|
|
896
|
+
* @param token - JWT token to decode
|
|
897
|
+
* @returns Decoded payload or null if invalid
|
|
898
|
+
*/
|
|
899
|
+
declare function decodeToken(token: string): TokenPayload | null;
|
|
900
|
+
/**
|
|
901
|
+
* Verify public key fingerprint matches
|
|
902
|
+
*
|
|
903
|
+
* Used during registration/login to ensure the public key wasn't tampered with
|
|
904
|
+
* during transmission.
|
|
905
|
+
*
|
|
906
|
+
* Security:
|
|
907
|
+
* - Client sends: publicKey + fingerprint
|
|
908
|
+
* - Server calculates: SHA-256(publicKey)
|
|
909
|
+
* - Server compares: calculated === received
|
|
910
|
+
*
|
|
911
|
+
* @param publicKeyB64 - Base64 encoded DER public key
|
|
912
|
+
* @param expectedFingerprint - SHA-256 hex fingerprint (64 chars)
|
|
913
|
+
* @returns True if fingerprint matches
|
|
914
|
+
*
|
|
915
|
+
* @example
|
|
916
|
+
* ```typescript
|
|
917
|
+
* const isValid = verifyKeyFingerprint(
|
|
918
|
+
* publicKey,
|
|
919
|
+
* 'a1b2c3d4e5f6...' // 64-char hex string
|
|
920
|
+
* );
|
|
921
|
+
* if (!isValid) {
|
|
922
|
+
* throw new Error('Public key fingerprint mismatch');
|
|
923
|
+
* }
|
|
924
|
+
* ```
|
|
925
|
+
*/
|
|
926
|
+
declare function verifyKeyFingerprint(publicKeyB64: string, expectedFingerprint: string): boolean;
|
|
927
|
+
|
|
928
|
+
/**
|
|
929
|
+
* @spfn/auth - Verification Code Helpers
|
|
930
|
+
*
|
|
931
|
+
* Helper functions for email/phone verification codes
|
|
932
|
+
*/
|
|
933
|
+
/**
|
|
934
|
+
* Verification token payload
|
|
935
|
+
*/
|
|
936
|
+
interface VerificationTokenPayload {
|
|
937
|
+
target: string;
|
|
938
|
+
targetType: 'email' | 'phone';
|
|
939
|
+
purpose: 'registration' | 'login' | 'password_reset';
|
|
940
|
+
codeId: number;
|
|
941
|
+
}
|
|
942
|
+
/**
|
|
943
|
+
* Generate a random 6-digit verification code
|
|
944
|
+
*
|
|
945
|
+
* @returns 6-digit code as string
|
|
946
|
+
*/
|
|
947
|
+
declare function generateVerificationCode(): string;
|
|
948
|
+
/**
|
|
949
|
+
* Store verification code in database
|
|
950
|
+
*
|
|
951
|
+
* @param target - Email or phone number
|
|
952
|
+
* @param targetType - Type of target (email or phone)
|
|
953
|
+
* @param code - 6-digit verification code
|
|
954
|
+
* @param purpose - Purpose of verification
|
|
955
|
+
* @returns Created verification code record
|
|
956
|
+
*/
|
|
957
|
+
declare function storeVerificationCode(target: string, targetType: 'email' | 'phone', code: string, purpose: 'registration' | 'login' | 'password_reset'): Promise<{
|
|
958
|
+
id: number;
|
|
959
|
+
createdAt: Date;
|
|
960
|
+
updatedAt: Date;
|
|
961
|
+
expiresAt: Date;
|
|
962
|
+
target: string;
|
|
963
|
+
targetType: "email" | "phone";
|
|
964
|
+
code: string;
|
|
965
|
+
purpose: "registration" | "login" | "password_reset" | "email_change" | "phone_change";
|
|
966
|
+
usedAt: Date | null;
|
|
967
|
+
attempts: string;
|
|
968
|
+
}>;
|
|
969
|
+
/**
|
|
970
|
+
* Validate verification code
|
|
971
|
+
*
|
|
972
|
+
* @param target - Email or phone number
|
|
973
|
+
* @param targetType - Type of target
|
|
974
|
+
* @param code - 6-digit code to validate
|
|
975
|
+
* @param purpose - Purpose of verification
|
|
976
|
+
* @returns Validation result with code ID if valid
|
|
977
|
+
*/
|
|
978
|
+
declare function validateVerificationCode(target: string, targetType: 'email' | 'phone', code: string, purpose: 'registration' | 'login' | 'password_reset'): Promise<{
|
|
979
|
+
valid: boolean;
|
|
980
|
+
codeId?: number;
|
|
981
|
+
error?: string;
|
|
982
|
+
}>;
|
|
983
|
+
/**
|
|
984
|
+
* Mark verification code as used
|
|
985
|
+
*
|
|
986
|
+
* @param codeId - Verification code ID
|
|
987
|
+
*/
|
|
988
|
+
declare function markCodeAsUsed(codeId: number): Promise<void>;
|
|
989
|
+
/**
|
|
990
|
+
* Create verification token (JWT)
|
|
991
|
+
*
|
|
992
|
+
* @param payload - Token payload
|
|
993
|
+
* @returns Signed JWT token
|
|
994
|
+
*/
|
|
995
|
+
declare function createVerificationToken(payload: VerificationTokenPayload): string;
|
|
996
|
+
/**
|
|
997
|
+
* Validate verification token (JWT)
|
|
998
|
+
*
|
|
999
|
+
* @param token - JWT token to validate
|
|
1000
|
+
* @returns Decoded payload if valid, null otherwise
|
|
1001
|
+
*/
|
|
1002
|
+
declare function validateVerificationToken(token: string): VerificationTokenPayload | null;
|
|
1003
|
+
/**
|
|
1004
|
+
* Send verification code via email
|
|
1005
|
+
*
|
|
1006
|
+
* @param email - Email address
|
|
1007
|
+
* @param code - 6-digit verification code
|
|
1008
|
+
* @param purpose - Purpose of verification
|
|
1009
|
+
*/
|
|
1010
|
+
declare function sendVerificationEmail(email: string, code: string, purpose: string): Promise<void>;
|
|
1011
|
+
/**
|
|
1012
|
+
* Send verification code via SMS
|
|
1013
|
+
*
|
|
1014
|
+
* @param phone - Phone number in E.164 format
|
|
1015
|
+
* @param code - 6-digit verification code
|
|
1016
|
+
* @param purpose - Purpose of verification
|
|
1017
|
+
*/
|
|
1018
|
+
declare function sendVerificationSMS(phone: string, code: string, purpose: string): Promise<void>;
|
|
1019
|
+
|
|
1020
|
+
/**
|
|
1021
|
+
* @spfn/auth - Authentication Middleware
|
|
1022
|
+
*
|
|
1023
|
+
* Verify client-signed JWT token with public key
|
|
1024
|
+
*
|
|
1025
|
+
* Flow:
|
|
1026
|
+
* 1. Extract Authorization header
|
|
1027
|
+
* 2. Decode JWT to extract keyId
|
|
1028
|
+
* 3. Fetch public key from database
|
|
1029
|
+
* 4. Check key expiration
|
|
1030
|
+
* 5. Verify JWT signature with public key
|
|
1031
|
+
* 6. Validate user status
|
|
1032
|
+
* 7. Update last used timestamp
|
|
1033
|
+
* 8. Attach user to context
|
|
1034
|
+
*
|
|
1035
|
+
* Security Checks:
|
|
1036
|
+
* - Token signature verification
|
|
1037
|
+
* - Key expiration check
|
|
1038
|
+
* - User status check (active/inactive/suspended)
|
|
1039
|
+
* - Key revocation check (isActive flag)
|
|
1040
|
+
*/
|
|
1041
|
+
|
|
1042
|
+
interface AuthContext {
|
|
1043
|
+
user: User;
|
|
1044
|
+
userId: string;
|
|
1045
|
+
keyId: string;
|
|
1046
|
+
}
|
|
1047
|
+
declare module 'hono' {
|
|
1048
|
+
interface ContextVariableMap {
|
|
1049
|
+
auth: AuthContext;
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
/**
|
|
1053
|
+
* Authentication middleware
|
|
1054
|
+
*
|
|
1055
|
+
* Verifies client-signed JWT token using stored public key
|
|
1056
|
+
* Must be applied to routes that require authentication
|
|
1057
|
+
*
|
|
1058
|
+
* @example
|
|
1059
|
+
* ```typescript
|
|
1060
|
+
* // In route file
|
|
1061
|
+
* app.bind(logoutContract, [authenticate], async (c) => {
|
|
1062
|
+
* const auth = c.raw.get('auth'); // Get auth context
|
|
1063
|
+
* const { user, userId, keyId } = auth;
|
|
1064
|
+
* // Or access directly: c.raw.get('auth').user
|
|
1065
|
+
* });
|
|
1066
|
+
* ```
|
|
1067
|
+
*/
|
|
1068
|
+
declare function authenticate(c: Context, next: Next): Promise<Response | void>;
|
|
1069
|
+
|
|
1070
|
+
/**
|
|
1071
|
+
* Auth Context Helpers
|
|
1072
|
+
*
|
|
1073
|
+
* Helper functions to access authenticated user data from route context
|
|
1074
|
+
*/
|
|
1075
|
+
|
|
1076
|
+
/**
|
|
1077
|
+
* Get auth context from route context
|
|
1078
|
+
*
|
|
1079
|
+
* Accepts both raw Hono Context and RouteContext with raw property
|
|
1080
|
+
*
|
|
1081
|
+
* @example
|
|
1082
|
+
* ```typescript
|
|
1083
|
+
* // With RouteContext (RPC routes)
|
|
1084
|
+
* app.bind(logoutContract, [authenticate], async (c) => {
|
|
1085
|
+
* const { user, userId, keyId } = getAuth(c);
|
|
1086
|
+
* // Use authenticated data...
|
|
1087
|
+
* });
|
|
1088
|
+
*
|
|
1089
|
+
* // With raw Context (middleware)
|
|
1090
|
+
* const auth = getAuth(c);
|
|
1091
|
+
* ```
|
|
1092
|
+
*/
|
|
1093
|
+
declare function getAuth(c: Context | {
|
|
1094
|
+
raw: Context;
|
|
1095
|
+
}): AuthContext;
|
|
1096
|
+
/**
|
|
1097
|
+
* Get authenticated user from route context
|
|
1098
|
+
*
|
|
1099
|
+
* @example
|
|
1100
|
+
* ```typescript
|
|
1101
|
+
* app.bind(profileContract, [authenticate], async (c) => {
|
|
1102
|
+
* const user = getUser(c);
|
|
1103
|
+
* return c.success({ email: user.email });
|
|
1104
|
+
* });
|
|
1105
|
+
* ```
|
|
1106
|
+
*/
|
|
1107
|
+
declare function getUser(c: Context | {
|
|
1108
|
+
raw: Context;
|
|
1109
|
+
}): {
|
|
1110
|
+
id: number;
|
|
1111
|
+
createdAt: Date;
|
|
1112
|
+
updatedAt: Date;
|
|
1113
|
+
email: string | null;
|
|
1114
|
+
phone: string | null;
|
|
1115
|
+
passwordHash: string | null;
|
|
1116
|
+
passwordChangeRequired: boolean;
|
|
1117
|
+
roleId: number;
|
|
1118
|
+
status: "active" | "inactive" | "suspended";
|
|
1119
|
+
emailVerifiedAt: Date | null;
|
|
1120
|
+
phoneVerifiedAt: Date | null;
|
|
1121
|
+
lastLoginAt: Date | null;
|
|
1122
|
+
};
|
|
1123
|
+
/**
|
|
1124
|
+
* Get authenticated user ID from route context
|
|
1125
|
+
*
|
|
1126
|
+
* @example
|
|
1127
|
+
* ```typescript
|
|
1128
|
+
* app.bind(postsContract, [authenticate], async (c) => {
|
|
1129
|
+
* const userId = getUserId(c);
|
|
1130
|
+
* const posts = await findPosts({ authorId: userId });
|
|
1131
|
+
* });
|
|
1132
|
+
* ```
|
|
1133
|
+
*/
|
|
1134
|
+
declare function getUserId(c: Context | {
|
|
1135
|
+
raw: Context;
|
|
1136
|
+
}): string;
|
|
1137
|
+
/**
|
|
1138
|
+
* Get current key ID from route context
|
|
1139
|
+
*
|
|
1140
|
+
* @example
|
|
1141
|
+
* ```typescript
|
|
1142
|
+
* app.bind(rotateKeyContract, [authenticate], async (c) => {
|
|
1143
|
+
* const oldKeyId = getKeyId(c);
|
|
1144
|
+
* // Revoke old key...
|
|
1145
|
+
* });
|
|
1146
|
+
* ```
|
|
1147
|
+
*/
|
|
1148
|
+
declare function getKeyId(c: Context | {
|
|
1149
|
+
raw: Context;
|
|
1150
|
+
}): string;
|
|
1151
|
+
|
|
1152
|
+
/**
|
|
1153
|
+
* @spfn/auth - Permission Middleware
|
|
1154
|
+
*
|
|
1155
|
+
* Middleware functions for permission-based access control
|
|
1156
|
+
*/
|
|
1157
|
+
|
|
1158
|
+
/**
|
|
1159
|
+
* Require user to have all specified permissions
|
|
1160
|
+
*
|
|
1161
|
+
* Must be used after authenticate middleware
|
|
1162
|
+
*
|
|
1163
|
+
* @param permissionNames - Permission names (e.g., 'user:delete', 'post:publish')
|
|
1164
|
+
* @returns Middleware function
|
|
1165
|
+
*
|
|
1166
|
+
* @example
|
|
1167
|
+
* ```typescript
|
|
1168
|
+
* app.bind(
|
|
1169
|
+
* deleteUserContract,
|
|
1170
|
+
* [authenticate, requirePermissions('user:delete')],
|
|
1171
|
+
* async (c) => {
|
|
1172
|
+
* // Only users with user:delete permission
|
|
1173
|
+
* }
|
|
1174
|
+
* );
|
|
1175
|
+
*
|
|
1176
|
+
* // Multiple permissions (all required)
|
|
1177
|
+
* app.bind(
|
|
1178
|
+
* publishPostContract,
|
|
1179
|
+
* [authenticate, requirePermissions('post:write', 'post:publish')],
|
|
1180
|
+
* async (c) => {
|
|
1181
|
+
* // Needs both permissions
|
|
1182
|
+
* }
|
|
1183
|
+
* );
|
|
1184
|
+
* ```
|
|
1185
|
+
*/
|
|
1186
|
+
declare function requirePermissions(...permissionNames: string[]): (c: Context, next: Next) => Promise<void>;
|
|
1187
|
+
/**
|
|
1188
|
+
* Require user to have at least one of the specified permissions
|
|
1189
|
+
*
|
|
1190
|
+
* Must be used after authenticate middleware
|
|
1191
|
+
*
|
|
1192
|
+
* @param permissionNames - Permission names
|
|
1193
|
+
* @returns Middleware function
|
|
1194
|
+
*
|
|
1195
|
+
* @example
|
|
1196
|
+
* ```typescript
|
|
1197
|
+
* app.bind(
|
|
1198
|
+
* viewContentContract,
|
|
1199
|
+
* [authenticate, requireAnyPermission('content:read', 'admin:access')],
|
|
1200
|
+
* async (c) => {
|
|
1201
|
+
* // User has either content:read OR admin:access
|
|
1202
|
+
* }
|
|
1203
|
+
* );
|
|
1204
|
+
* ```
|
|
1205
|
+
*/
|
|
1206
|
+
declare function requireAnyPermission(...permissionNames: string[]): (c: Context, next: Next) => Promise<void>;
|
|
1207
|
+
|
|
1208
|
+
/**
|
|
1209
|
+
* @spfn/auth - Role Middleware
|
|
1210
|
+
*
|
|
1211
|
+
* Middleware functions for role-based access control
|
|
1212
|
+
*/
|
|
1213
|
+
|
|
1214
|
+
/**
|
|
1215
|
+
* Require user to have one of the specified roles
|
|
1216
|
+
*
|
|
1217
|
+
* Must be used after authenticate middleware
|
|
1218
|
+
*
|
|
1219
|
+
* @param roleNames - Role names (e.g., 'admin', 'superadmin')
|
|
1220
|
+
* @returns Middleware function
|
|
1221
|
+
*
|
|
1222
|
+
* @example
|
|
1223
|
+
* ```typescript
|
|
1224
|
+
* app.bind(
|
|
1225
|
+
* adminDashboardContract,
|
|
1226
|
+
* [authenticate, requireRole('admin', 'superadmin')],
|
|
1227
|
+
* async (c) => {
|
|
1228
|
+
* // Only admin or superadmin
|
|
1229
|
+
* }
|
|
1230
|
+
* );
|
|
1231
|
+
*
|
|
1232
|
+
* // Single role
|
|
1233
|
+
* app.bind(
|
|
1234
|
+
* systemConfigContract,
|
|
1235
|
+
* [authenticate, requireRole('superadmin')],
|
|
1236
|
+
* async (c) => {
|
|
1237
|
+
* // Only superadmin
|
|
1238
|
+
* }
|
|
1239
|
+
* );
|
|
1240
|
+
* ```
|
|
1241
|
+
*/
|
|
1242
|
+
declare function requireRole(...roleNames: string[]): (c: Context, next: Next) => Promise<void>;
|
|
1243
|
+
|
|
1244
|
+
/**
|
|
1245
|
+
* @spfn/auth - Setup Functions
|
|
1246
|
+
*
|
|
1247
|
+
* Initial setup and admin account creation
|
|
1248
|
+
*/
|
|
1249
|
+
/**
|
|
1250
|
+
* Ensure admin accounts exist from environment variables
|
|
1251
|
+
*
|
|
1252
|
+
* Supports multiple admin account creation via three formats:
|
|
1253
|
+
* 1. JSON format (SPFN_AUTH_ADMIN_ACCOUNTS)
|
|
1254
|
+
* 2. Comma-separated format (SPFN_AUTH_ADMIN_EMAILS + SPFN_AUTH_ADMIN_PASSWORDS + SPFN_AUTH_ADMIN_ROLES)
|
|
1255
|
+
* 3. Single account format (SPFN_AUTH_ADMIN_EMAIL + SPFN_AUTH_ADMIN_PASSWORD) - legacy
|
|
1256
|
+
*
|
|
1257
|
+
* Default behavior for created accounts:
|
|
1258
|
+
* - emailVerifiedAt: current timestamp (auto-verified)
|
|
1259
|
+
* - passwordChangeRequired: true (must change on first login)
|
|
1260
|
+
* - status: 'active'
|
|
1261
|
+
*
|
|
1262
|
+
* @example
|
|
1263
|
+
* ```typescript
|
|
1264
|
+
* // In your server startup code:
|
|
1265
|
+
* import { ensureAdminExists } from '@spfn/auth/server';
|
|
1266
|
+
*
|
|
1267
|
+
* await ensureAdminExists();
|
|
1268
|
+
* ```
|
|
1269
|
+
*/
|
|
1270
|
+
declare function ensureAdminExists(): Promise<void>;
|
|
1271
|
+
|
|
1272
|
+
export { type AuthContext, type AuthInitOptions, BUILTIN_PERMISSIONS, BUILTIN_ROLES, BUILTIN_ROLE_PERMISSIONS, type BuiltinPermissionName, type BuiltinRoleName, type ChangePasswordParams, type CheckAccountExistsParams, type CheckAccountExistsResult, type GetMeResult, type LoginParams, type LoginResult, type LogoutParams, type PermissionConfig, type RegisterParams, type RegisterPublicKeyParams, type RegisterResult, type RevokeKeyParams, type RoleConfig, type RotateKeyParams, type RotateKeyResult, type SendVerificationCodeParams, type SendVerificationCodeResult, type TokenPayload, type VerificationTokenPayload, type VerifyCodeParams, type VerifyCodeResult, acceptInvitation, addPermissionToRole, authenticate, cancelInvitation, changePasswordService, checkAccountExistsService, createInvitation, createRole, createVerificationToken, decodeToken, deleteInvitation, deleteRole, ensureAdminExists, expireOldInvitations, generateToken, generateVerificationCode, getAllRoles, getAuth, getInvitationByToken, getInvitationWithDetails, getKeyId, getMeService, getRoleByName, getRolePermissions, getUser, getUserByEmailService, getUserByIdService, getUserByPhoneService, getUserId, getUserPermissions, hasAllPermissions, hasAnyPermission, hasAnyRole, hasPermission, hasRole, hashPassword, initializeAuth, listInvitations, loginService, logoutService, markCodeAsUsed, registerPublicKeyService, registerService, removePermissionFromRole, requireAnyPermission, requirePermissions, requireRole, resendInvitation, revokeKeyService, rotateKeyService, sendVerificationCodeService, sendVerificationEmail, sendVerificationSMS, setRolePermissions, storeVerificationCode, updateLastLoginService, updateRole, updateUserService, validateInvitation, validatePasswordStrength, validateVerificationCode, validateVerificationToken, verifyClientToken, verifyCodeService, verifyKeyFingerprint, verifyPassword, verifyToken };
|