@mostajs/auth 2.0.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +35 -58
- package/dist/index.d.ts +5 -0
- package/dist/lib/apikey-provider.d.ts +32 -0
- package/dist/lib/apikey-provider.js +34 -0
- package/dist/lib/email-verification.d.ts +24 -0
- package/dist/lib/email-verification.js +38 -0
- package/dist/lib/password-reset.d.ts +26 -0
- package/dist/lib/password-reset.js +49 -0
- package/dist/lib/registration.d.ts +18 -0
- package/dist/lib/registration.js +30 -0
- package/dist/lib/session-enrichment.d.ts +16 -0
- package/dist/lib/session-enrichment.js +47 -0
- package/dist/server.d.ts +13 -0
- package/dist/server.js +14 -0
- package/package.json +27 -2
package/README.md
CHANGED
|
@@ -1,87 +1,64 @@
|
|
|
1
1
|
# @mostajs/auth
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> NextAuth authentication with RBAC — delegates user management to @mostajs/rbac.
|
|
4
|
+
> Author: Dr Hamid MADANI drmdh@msn.com
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
[](LICENSE)
|
|
7
|
-
|
|
8
|
-
Part of the [@mosta suite](https://mostajs.dev).
|
|
9
|
-
|
|
10
|
-
---
|
|
11
|
-
|
|
12
|
-
## Installation
|
|
6
|
+
## Install
|
|
13
7
|
|
|
14
8
|
```bash
|
|
15
|
-
npm install @mostajs/auth @mostajs/
|
|
9
|
+
npm install @mostajs/auth @mostajs/rbac next-auth@5.0.0-beta.25
|
|
16
10
|
```
|
|
17
11
|
|
|
18
|
-
##
|
|
19
|
-
|
|
20
|
-
### 1. Register schemas
|
|
21
|
-
|
|
22
|
-
```typescript
|
|
23
|
-
import { registerSchemas } from '@mostajs/orm'
|
|
24
|
-
import { UserSchema, RoleSchema, PermissionSchema, PermissionCategorySchema } from '@mostajs/auth'
|
|
25
|
-
|
|
26
|
-
registerSchemas([UserSchema, RoleSchema, PermissionSchema, PermissionCategorySchema])
|
|
27
|
-
```
|
|
12
|
+
## How to Use
|
|
28
13
|
|
|
29
|
-
###
|
|
14
|
+
### 1. Create Auth Handlers
|
|
30
15
|
|
|
31
16
|
```typescript
|
|
32
|
-
|
|
17
|
+
// src/lib/auth.ts
|
|
18
|
+
import { createAuthHandlers } from '@mostajs/auth/server'
|
|
33
19
|
|
|
34
20
|
const ROLE_PERMISSIONS = {
|
|
35
21
|
admin: ['*'],
|
|
36
|
-
|
|
22
|
+
agent: ['client:view', 'ticket:create'],
|
|
37
23
|
}
|
|
38
24
|
|
|
39
|
-
const { handlers, auth, signIn, signOut } = createAuthHandlers(ROLE_PERMISSIONS
|
|
40
|
-
|
|
25
|
+
const { handlers, auth, signIn, signOut } = createAuthHandlers(ROLE_PERMISSIONS, {
|
|
26
|
+
pages: { signIn: '/login', error: '/login' },
|
|
27
|
+
})
|
|
41
28
|
|
|
42
|
-
export { handlers, auth,
|
|
29
|
+
export { handlers, auth, signIn, signOut }
|
|
43
30
|
```
|
|
44
31
|
|
|
45
|
-
###
|
|
32
|
+
### 2. Auth Checks in API Routes
|
|
46
33
|
|
|
47
34
|
```typescript
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
if (error) return error
|
|
51
|
-
// ...
|
|
52
|
-
}
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
### 4. Client-side permission guard
|
|
35
|
+
import { createAuthChecks } from '@mostajs/auth/server'
|
|
36
|
+
import { auth } from '@/lib/auth'
|
|
56
37
|
|
|
57
|
-
|
|
58
|
-
import PermissionGuard from '@mostajs/auth/components/PermissionGuard'
|
|
38
|
+
const { checkAuth, checkPermission } = createAuthChecks(auth, ROLE_PERMISSIONS)
|
|
59
39
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
40
|
+
// In API route:
|
|
41
|
+
const { error } = await checkPermission('client:view')
|
|
42
|
+
if (error) return error
|
|
63
43
|
```
|
|
64
44
|
|
|
65
|
-
|
|
45
|
+
### 3. Middleware
|
|
66
46
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
| `createAuthMiddleware()` | Next.js middleware for route protection |
|
|
72
|
-
| `seedRBAC()` | Idempotent seed of categories, permissions, roles |
|
|
73
|
-
| `hashPassword()` / `comparePassword()` | bcryptjs wrappers |
|
|
74
|
-
| `hasPermission()` / `getPermissionsForRole()` | Client-safe permission helpers |
|
|
75
|
-
| `usePermissions()` | React hook for permission checking |
|
|
76
|
-
| `PermissionGuard` | Conditional render component |
|
|
77
|
-
| `SessionProvider` | NextAuth session wrapper |
|
|
78
|
-
| `UserRepository` / `RoleRepository` / `PermissionRepository` | Database repositories |
|
|
47
|
+
```typescript
|
|
48
|
+
import { createAuthMiddleware } from '@mostajs/auth/server'
|
|
49
|
+
export default createAuthMiddleware({ publicPaths: ['/login'], protectedPrefixes: ['/dashboard'] })
|
|
50
|
+
```
|
|
79
51
|
|
|
80
|
-
|
|
52
|
+
### 4. Create Admin (delegates to rbac)
|
|
81
53
|
|
|
82
|
-
|
|
83
|
-
|
|
54
|
+
```typescript
|
|
55
|
+
import { createAdmin } from '@mostajs/auth/server'
|
|
56
|
+
await createAdmin({ email: 'admin@test.com', password: 'Admin123!', firstName: 'Admin', lastName: 'Test' })
|
|
57
|
+
```
|
|
84
58
|
|
|
85
|
-
|
|
59
|
+
### 5. Client Components
|
|
86
60
|
|
|
87
|
-
|
|
61
|
+
```typescript
|
|
62
|
+
import { usePermissions } from '@mostajs/auth'
|
|
63
|
+
import { PermissionGuard, SessionProvider } from '@mostajs/auth'
|
|
64
|
+
```
|
package/dist/index.d.ts
CHANGED
|
@@ -5,3 +5,8 @@ export { default as PermissionGuard } from './components/PermissionGuard';
|
|
|
5
5
|
export { default as SessionProvider } from './components/SessionProvider';
|
|
6
6
|
export type { UserDTO, RoleDTO, PermissionDTO, PermissionCategoryDTO, PermissionDefinition, RoleDefinition, CategoryDefinition, } from '@mostajs/rbac';
|
|
7
7
|
export type { MostaAuthConfig } from './types/index';
|
|
8
|
+
export type { RegistrationConfig } from './lib/registration';
|
|
9
|
+
export type { VerificationConfig } from './lib/email-verification';
|
|
10
|
+
export type { PasswordResetConfig } from './lib/password-reset';
|
|
11
|
+
export type { ApiKeyProviderConfig } from './lib/apikey-provider';
|
|
12
|
+
export type { SessionEnrichmentConfig } from './lib/session-enrichment';
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates a NextAuth credentials provider that authenticates via API key
|
|
3
|
+
* instead of email/password. Used for programmatic access.
|
|
4
|
+
*/
|
|
5
|
+
export interface ApiKeyProviderConfig {
|
|
6
|
+
/** Function to resolve API key (from @mostajs/api-keys) */
|
|
7
|
+
resolveApiKey: (rawKey: string) => Promise<any | null>;
|
|
8
|
+
/** Function to load account by ID */
|
|
9
|
+
loadAccount: (accountId: string) => Promise<any | null>;
|
|
10
|
+
/** Function to get permissions for account */
|
|
11
|
+
getPermissions?: (account: any) => Promise<string[]>;
|
|
12
|
+
}
|
|
13
|
+
export declare function createApiKeyProvider(config: ApiKeyProviderConfig): {
|
|
14
|
+
id: string;
|
|
15
|
+
name: string;
|
|
16
|
+
type: "credentials";
|
|
17
|
+
credentials: {
|
|
18
|
+
apiKey: {
|
|
19
|
+
label: string;
|
|
20
|
+
type: string;
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
authorize(credentials: any): Promise<{
|
|
24
|
+
id: any;
|
|
25
|
+
email: any;
|
|
26
|
+
name: any;
|
|
27
|
+
role: any;
|
|
28
|
+
roles: any[];
|
|
29
|
+
permissions: string[];
|
|
30
|
+
apiKeyId: any;
|
|
31
|
+
} | null>;
|
|
32
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// @mostajs/auth — API key authentication provider for NextAuth
|
|
2
|
+
// Author: Dr Hamid MADANI drmdh@msn.com
|
|
3
|
+
export function createApiKeyProvider(config) {
|
|
4
|
+
return {
|
|
5
|
+
id: 'api-key',
|
|
6
|
+
name: 'API Key',
|
|
7
|
+
type: 'credentials',
|
|
8
|
+
credentials: {
|
|
9
|
+
apiKey: { label: 'API Key', type: 'text' },
|
|
10
|
+
},
|
|
11
|
+
async authorize(credentials) {
|
|
12
|
+
if (!credentials?.apiKey)
|
|
13
|
+
return null;
|
|
14
|
+
const apiKey = await config.resolveApiKey(credentials.apiKey);
|
|
15
|
+
if (!apiKey)
|
|
16
|
+
return null;
|
|
17
|
+
const account = await config.loadAccount(apiKey.accountId);
|
|
18
|
+
if (!account || account.banned)
|
|
19
|
+
return null;
|
|
20
|
+
const permissions = config.getPermissions
|
|
21
|
+
? await config.getPermissions(account)
|
|
22
|
+
: [];
|
|
23
|
+
return {
|
|
24
|
+
id: account.id ?? account._id,
|
|
25
|
+
email: account.email,
|
|
26
|
+
name: account.name,
|
|
27
|
+
role: account.role ?? 'user',
|
|
28
|
+
roles: [account.role ?? 'user'],
|
|
29
|
+
permissions,
|
|
30
|
+
apiKeyId: apiKey.id ?? apiKey._id,
|
|
31
|
+
};
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface VerificationConfig {
|
|
2
|
+
/** Function to update account with verify token */
|
|
3
|
+
updateAccount: (id: string, data: any) => Promise<void>;
|
|
4
|
+
/** Function to find account by verify token */
|
|
5
|
+
findByVerifyToken: (token: string) => Promise<any | null>;
|
|
6
|
+
/** Function to send verification email */
|
|
7
|
+
sendEmail?: (to: string, token: string, verifyUrl: string) => Promise<void>;
|
|
8
|
+
/** Base URL for verify link */
|
|
9
|
+
verifyBaseUrl: string;
|
|
10
|
+
/** Token expiry in hours (default 24) */
|
|
11
|
+
tokenExpiryHours?: number;
|
|
12
|
+
}
|
|
13
|
+
export declare function generateVerifyToken(): string;
|
|
14
|
+
export declare function createVerificationHandlers(config: VerificationConfig): {
|
|
15
|
+
sendVerification: (accountId: string, email: string) => Promise<{
|
|
16
|
+
token: string;
|
|
17
|
+
url: string;
|
|
18
|
+
}>;
|
|
19
|
+
verifyEmail: (token: string) => Promise<{
|
|
20
|
+
ok: boolean;
|
|
21
|
+
error?: string;
|
|
22
|
+
}>;
|
|
23
|
+
generateVerifyToken: typeof generateVerifyToken;
|
|
24
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// @mostajs/auth — Email verification
|
|
2
|
+
// Author: Dr Hamid MADANI drmdh@msn.com
|
|
3
|
+
import crypto from 'node:crypto';
|
|
4
|
+
export function generateVerifyToken() {
|
|
5
|
+
return crypto.randomBytes(32).toString('hex');
|
|
6
|
+
}
|
|
7
|
+
export function createVerificationHandlers(config) {
|
|
8
|
+
/** POST /auth/send-verification — Send verification email */
|
|
9
|
+
async function sendVerification(accountId, email) {
|
|
10
|
+
const token = generateVerifyToken();
|
|
11
|
+
const expiresAt = new Date(Date.now() + (config.tokenExpiryHours ?? 24) * 3600000).toISOString();
|
|
12
|
+
await config.updateAccount(accountId, { verifyToken: token, verifyTokenExpiresAt: expiresAt });
|
|
13
|
+
const url = `${config.verifyBaseUrl}?token=${token}`;
|
|
14
|
+
if (config.sendEmail) {
|
|
15
|
+
await config.sendEmail(email, token, url);
|
|
16
|
+
}
|
|
17
|
+
return { token, url };
|
|
18
|
+
}
|
|
19
|
+
/** GET /auth/verify?token=xxx — Verify email */
|
|
20
|
+
async function verifyEmail(token) {
|
|
21
|
+
if (!token)
|
|
22
|
+
return { ok: false, error: 'Token required' };
|
|
23
|
+
const account = await config.findByVerifyToken(token);
|
|
24
|
+
if (!account)
|
|
25
|
+
return { ok: false, error: 'Invalid or expired token' };
|
|
26
|
+
// Check expiry
|
|
27
|
+
if (account.verifyTokenExpiresAt && new Date(account.verifyTokenExpiresAt) < new Date()) {
|
|
28
|
+
return { ok: false, error: 'Token expired' };
|
|
29
|
+
}
|
|
30
|
+
await config.updateAccount(account.id ?? account._id, {
|
|
31
|
+
verified: true,
|
|
32
|
+
verifyToken: null,
|
|
33
|
+
verifyTokenExpiresAt: null,
|
|
34
|
+
});
|
|
35
|
+
return { ok: true };
|
|
36
|
+
}
|
|
37
|
+
return { sendVerification, verifyEmail, generateVerifyToken };
|
|
38
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export interface PasswordResetConfig {
|
|
2
|
+
/** Find account by email */
|
|
3
|
+
findByEmail: (email: string) => Promise<any | null>;
|
|
4
|
+
/** Find account by reset token */
|
|
5
|
+
findByResetToken: (token: string) => Promise<any | null>;
|
|
6
|
+
/** Update account data */
|
|
7
|
+
updateAccount: (id: string, data: any) => Promise<void>;
|
|
8
|
+
/** Send reset email */
|
|
9
|
+
sendEmail?: (to: string, token: string, resetUrl: string) => Promise<void>;
|
|
10
|
+
/** Base URL for reset link */
|
|
11
|
+
resetBaseUrl: string;
|
|
12
|
+
/** Token expiry in hours (default 1) */
|
|
13
|
+
tokenExpiryHours?: number;
|
|
14
|
+
}
|
|
15
|
+
export declare function generateResetToken(): string;
|
|
16
|
+
export declare function createPasswordResetHandlers(config: PasswordResetConfig): {
|
|
17
|
+
forgotPassword: (email: string) => Promise<{
|
|
18
|
+
ok: boolean;
|
|
19
|
+
error?: string;
|
|
20
|
+
}>;
|
|
21
|
+
resetPassword: (token: string, newPassword: string) => Promise<{
|
|
22
|
+
ok: boolean;
|
|
23
|
+
error?: string;
|
|
24
|
+
}>;
|
|
25
|
+
generateResetToken: typeof generateResetToken;
|
|
26
|
+
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// @mostajs/auth — Password reset
|
|
2
|
+
// Author: Dr Hamid MADANI drmdh@msn.com
|
|
3
|
+
import crypto from 'node:crypto';
|
|
4
|
+
import { hashPassword } from './password.js';
|
|
5
|
+
export function generateResetToken() {
|
|
6
|
+
return crypto.randomBytes(32).toString('hex');
|
|
7
|
+
}
|
|
8
|
+
export function createPasswordResetHandlers(config) {
|
|
9
|
+
/** POST /auth/forgot-password — Request password reset */
|
|
10
|
+
async function forgotPassword(email) {
|
|
11
|
+
const account = await config.findByEmail(email);
|
|
12
|
+
if (!account) {
|
|
13
|
+
// Don't reveal if email exists
|
|
14
|
+
return { ok: true };
|
|
15
|
+
}
|
|
16
|
+
const token = generateResetToken();
|
|
17
|
+
const expiresAt = new Date(Date.now() + (config.tokenExpiryHours ?? 1) * 3600000).toISOString();
|
|
18
|
+
await config.updateAccount(account.id ?? account._id, {
|
|
19
|
+
resetToken: token,
|
|
20
|
+
resetTokenExpiresAt: expiresAt,
|
|
21
|
+
});
|
|
22
|
+
const url = `${config.resetBaseUrl}?token=${token}`;
|
|
23
|
+
if (config.sendEmail) {
|
|
24
|
+
await config.sendEmail(email, token, url);
|
|
25
|
+
}
|
|
26
|
+
return { ok: true };
|
|
27
|
+
}
|
|
28
|
+
/** POST /auth/reset-password — Reset password with token */
|
|
29
|
+
async function resetPassword(token, newPassword) {
|
|
30
|
+
if (!token || !newPassword)
|
|
31
|
+
return { ok: false, error: 'Token and new password required' };
|
|
32
|
+
if (newPassword.length < 8)
|
|
33
|
+
return { ok: false, error: 'Password must be at least 8 characters' };
|
|
34
|
+
const account = await config.findByResetToken(token);
|
|
35
|
+
if (!account)
|
|
36
|
+
return { ok: false, error: 'Invalid or expired token' };
|
|
37
|
+
if (account.resetTokenExpiresAt && new Date(account.resetTokenExpiresAt) < new Date()) {
|
|
38
|
+
return { ok: false, error: 'Token expired' };
|
|
39
|
+
}
|
|
40
|
+
const hashed = await hashPassword(newPassword);
|
|
41
|
+
await config.updateAccount(account.id ?? account._id, {
|
|
42
|
+
password: hashed,
|
|
43
|
+
resetToken: null,
|
|
44
|
+
resetTokenExpiresAt: null,
|
|
45
|
+
});
|
|
46
|
+
return { ok: true };
|
|
47
|
+
}
|
|
48
|
+
return { forgotPassword, resetPassword, generateResetToken };
|
|
49
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface RegistrationConfig {
|
|
2
|
+
/** Function to create account in DB (returns created account) */
|
|
3
|
+
createAccount: (data: {
|
|
4
|
+
email: string;
|
|
5
|
+
name: string;
|
|
6
|
+
password: string;
|
|
7
|
+
role?: string;
|
|
8
|
+
}) => Promise<any>;
|
|
9
|
+
/** Function to check if email already exists */
|
|
10
|
+
findByEmail: (email: string) => Promise<any | null>;
|
|
11
|
+
/** Default role for new users */
|
|
12
|
+
defaultRole?: string;
|
|
13
|
+
/** Default plan slug for new subscription */
|
|
14
|
+
defaultPlan?: string;
|
|
15
|
+
/** Called after successful registration */
|
|
16
|
+
onRegistered?: (account: any) => Promise<void>;
|
|
17
|
+
}
|
|
18
|
+
export declare function createRegistrationHandler(config: RegistrationConfig): (req: Request) => Promise<Response>;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// @mostajs/auth — Registration handler
|
|
2
|
+
// Author: Dr Hamid MADANI drmdh@msn.com
|
|
3
|
+
import { hashPassword } from './password.js';
|
|
4
|
+
export function createRegistrationHandler(config) {
|
|
5
|
+
return async function POST(req) {
|
|
6
|
+
const body = await req.json();
|
|
7
|
+
if (!body.email || !body.name || !body.password) {
|
|
8
|
+
return Response.json({ error: 'email, name, and password are required' }, { status: 400 });
|
|
9
|
+
}
|
|
10
|
+
if (body.password.length < 8) {
|
|
11
|
+
return Response.json({ error: 'Password must be at least 8 characters' }, { status: 400 });
|
|
12
|
+
}
|
|
13
|
+
// Check duplicate
|
|
14
|
+
const existing = await config.findByEmail(body.email);
|
|
15
|
+
if (existing) {
|
|
16
|
+
return Response.json({ error: 'Email already registered' }, { status: 409 });
|
|
17
|
+
}
|
|
18
|
+
const hashed = await hashPassword(body.password);
|
|
19
|
+
const account = await config.createAccount({
|
|
20
|
+
email: body.email,
|
|
21
|
+
name: body.name,
|
|
22
|
+
password: hashed,
|
|
23
|
+
role: config.defaultRole ?? 'user',
|
|
24
|
+
});
|
|
25
|
+
if (config.onRegistered) {
|
|
26
|
+
await config.onRegistered(account);
|
|
27
|
+
}
|
|
28
|
+
return Response.json({ ok: true, id: account.id ?? account._id }, { status: 201 });
|
|
29
|
+
};
|
|
30
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface SessionEnrichmentConfig {
|
|
2
|
+
/** Load subscription for account */
|
|
3
|
+
loadSubscription?: (accountId: string) => Promise<any | null>;
|
|
4
|
+
/** Load plan by ID */
|
|
5
|
+
loadPlan?: (planId: string) => Promise<any | null>;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Enrich a JWT token with plan and subscription data.
|
|
9
|
+
* Call this in the NextAuth jwt callback.
|
|
10
|
+
*/
|
|
11
|
+
export declare function enrichTokenWithPlan(token: any, config: SessionEnrichmentConfig): Promise<any>;
|
|
12
|
+
/**
|
|
13
|
+
* Copy plan data from token to session.
|
|
14
|
+
* Call this in the NextAuth session callback.
|
|
15
|
+
*/
|
|
16
|
+
export declare function enrichSessionWithPlan(session: any, token: any): any;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// @mostajs/auth — Session enrichment with plan/subscription data
|
|
2
|
+
// Author: Dr Hamid MADANI drmdh@msn.com
|
|
3
|
+
/**
|
|
4
|
+
* Enrich a JWT token with plan and subscription data.
|
|
5
|
+
* Call this in the NextAuth jwt callback.
|
|
6
|
+
*/
|
|
7
|
+
export async function enrichTokenWithPlan(token, config) {
|
|
8
|
+
if (!config.loadSubscription || !config.loadPlan)
|
|
9
|
+
return token;
|
|
10
|
+
if (!token.sub)
|
|
11
|
+
return token;
|
|
12
|
+
try {
|
|
13
|
+
const sub = await config.loadSubscription(token.sub);
|
|
14
|
+
if (sub) {
|
|
15
|
+
token.subscriptionStatus = sub.status;
|
|
16
|
+
token.subscriptionId = sub.id ?? sub._id;
|
|
17
|
+
const planId = sub.plan ?? sub.planId;
|
|
18
|
+
if (planId) {
|
|
19
|
+
const plan = await config.loadPlan(planId);
|
|
20
|
+
if (plan) {
|
|
21
|
+
token.planSlug = plan.slug;
|
|
22
|
+
token.planName = plan.name;
|
|
23
|
+
token.planLimits = typeof plan.limits === 'string' ? JSON.parse(plan.limits) : plan.limits;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
// Don't break auth if plan loading fails
|
|
30
|
+
}
|
|
31
|
+
return token;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Copy plan data from token to session.
|
|
35
|
+
* Call this in the NextAuth session callback.
|
|
36
|
+
*/
|
|
37
|
+
export function enrichSessionWithPlan(session, token) {
|
|
38
|
+
if (token.planSlug)
|
|
39
|
+
session.user.planSlug = token.planSlug;
|
|
40
|
+
if (token.planName)
|
|
41
|
+
session.user.planName = token.planName;
|
|
42
|
+
if (token.planLimits)
|
|
43
|
+
session.user.planLimits = token.planLimits;
|
|
44
|
+
if (token.subscriptionStatus)
|
|
45
|
+
session.user.subscriptionStatus = token.subscriptionStatus;
|
|
46
|
+
return session;
|
|
47
|
+
}
|
package/dist/server.d.ts
CHANGED
|
@@ -6,4 +6,17 @@ export { hashPassword, comparePassword } from './lib/password';
|
|
|
6
6
|
export { getPermissionsForRoleFromDB } from '@mostajs/rbac/lib/permissions-server';
|
|
7
7
|
export { seedRBAC } from '@mostajs/rbac/lib/rbac-seed';
|
|
8
8
|
export type { SeedRBACOptions } from '@mostajs/rbac/lib/rbac-seed';
|
|
9
|
+
export { createAdmin } from '@mostajs/rbac/lib/create-admin';
|
|
10
|
+
export type { CreateAdminOptions, CreateAdminResult } from '@mostajs/rbac/lib/create-admin';
|
|
11
|
+
export { getSchemas, moduleInfo } from '@mostajs/rbac/lib/module-info';
|
|
9
12
|
export { UserRepository, RoleRepository, PermissionRepository, PermissionCategoryRepository } from '@mostajs/rbac/server';
|
|
13
|
+
export { createRegistrationHandler } from './lib/registration';
|
|
14
|
+
export type { RegistrationConfig } from './lib/registration';
|
|
15
|
+
export { createVerificationHandlers, generateVerifyToken } from './lib/email-verification';
|
|
16
|
+
export type { VerificationConfig } from './lib/email-verification';
|
|
17
|
+
export { createPasswordResetHandlers, generateResetToken } from './lib/password-reset';
|
|
18
|
+
export type { PasswordResetConfig } from './lib/password-reset';
|
|
19
|
+
export { createApiKeyProvider } from './lib/apikey-provider';
|
|
20
|
+
export type { ApiKeyProviderConfig } from './lib/apikey-provider';
|
|
21
|
+
export { enrichTokenWithPlan, enrichSessionWithPlan } from './lib/session-enrichment';
|
|
22
|
+
export type { SessionEnrichmentConfig } from './lib/session-enrichment';
|
package/dist/server.js
CHANGED
|
@@ -11,5 +11,19 @@ export { hashPassword, comparePassword } from './lib/password';
|
|
|
11
11
|
export { getPermissionsForRoleFromDB } from '@mostajs/rbac/lib/permissions-server';
|
|
12
12
|
// RBAC seed (re-export from rbac/server)
|
|
13
13
|
export { seedRBAC } from '@mostajs/rbac/lib/rbac-seed';
|
|
14
|
+
// Create admin (re-export from rbac — auth delegates to rbac for user creation)
|
|
15
|
+
export { createAdmin } from '@mostajs/rbac/lib/create-admin';
|
|
16
|
+
// Module schemas (re-export from rbac — auth has no own schemas)
|
|
17
|
+
export { getSchemas, moduleInfo } from '@mostajs/rbac/lib/module-info';
|
|
14
18
|
// Repositories (re-export from rbac/server)
|
|
15
19
|
export { UserRepository, RoleRepository, PermissionRepository, PermissionCategoryRepository } from '@mostajs/rbac/server';
|
|
20
|
+
// Registration
|
|
21
|
+
export { createRegistrationHandler } from './lib/registration';
|
|
22
|
+
// Email verification
|
|
23
|
+
export { createVerificationHandlers, generateVerifyToken } from './lib/email-verification';
|
|
24
|
+
// Password reset
|
|
25
|
+
export { createPasswordResetHandlers, generateResetToken } from './lib/password-reset';
|
|
26
|
+
// API key provider
|
|
27
|
+
export { createApiKeyProvider } from './lib/apikey-provider';
|
|
28
|
+
// Session enrichment
|
|
29
|
+
export { enrichTokenWithPlan, enrichSessionWithPlan } from './lib/session-enrichment';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mostajs/auth",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "Authentication — NextAuth, password hashing, session management",
|
|
5
5
|
"author": "Dr Hamid MADANI <drmdh@msn.com>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -62,6 +62,31 @@
|
|
|
62
62
|
"types": "./dist/register.d.ts",
|
|
63
63
|
"import": "./dist/register.js",
|
|
64
64
|
"default": "./dist/register.js"
|
|
65
|
+
},
|
|
66
|
+
"./lib/registration": {
|
|
67
|
+
"types": "./dist/lib/registration.d.ts",
|
|
68
|
+
"import": "./dist/lib/registration.js",
|
|
69
|
+
"default": "./dist/lib/registration.js"
|
|
70
|
+
},
|
|
71
|
+
"./lib/email-verification": {
|
|
72
|
+
"types": "./dist/lib/email-verification.d.ts",
|
|
73
|
+
"import": "./dist/lib/email-verification.js",
|
|
74
|
+
"default": "./dist/lib/email-verification.js"
|
|
75
|
+
},
|
|
76
|
+
"./lib/password-reset": {
|
|
77
|
+
"types": "./dist/lib/password-reset.d.ts",
|
|
78
|
+
"import": "./dist/lib/password-reset.js",
|
|
79
|
+
"default": "./dist/lib/password-reset.js"
|
|
80
|
+
},
|
|
81
|
+
"./lib/apikey-provider": {
|
|
82
|
+
"types": "./dist/lib/apikey-provider.d.ts",
|
|
83
|
+
"import": "./dist/lib/apikey-provider.js",
|
|
84
|
+
"default": "./dist/lib/apikey-provider.js"
|
|
85
|
+
},
|
|
86
|
+
"./lib/session-enrichment": {
|
|
87
|
+
"types": "./dist/lib/session-enrichment.d.ts",
|
|
88
|
+
"import": "./dist/lib/session-enrichment.js",
|
|
89
|
+
"default": "./dist/lib/session-enrichment.js"
|
|
65
90
|
}
|
|
66
91
|
},
|
|
67
92
|
"files": [
|
|
@@ -104,7 +129,7 @@
|
|
|
104
129
|
"react": ">=18"
|
|
105
130
|
},
|
|
106
131
|
"devDependencies": {
|
|
107
|
-
"@mostajs/rbac": "^2.0.
|
|
132
|
+
"@mostajs/rbac": "^2.0.3",
|
|
108
133
|
"@types/bcryptjs": "^2.4.0",
|
|
109
134
|
"@types/node": "^25.3.3",
|
|
110
135
|
"@types/react": "^19.0.0",
|