najm-auth 4.0.2 → 4.0.3
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 +13 -13
- package/dist/index.d.ts +1 -5
- package/dist/index.js +3 -18
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -138,9 +138,8 @@ auth({
|
|
|
138
138
|
publicRegistration?: boolean // Default: true; mounts POST /auth/register
|
|
139
139
|
bcryptRounds?: number // Default: 10 (valid: 4-31)
|
|
140
140
|
|
|
141
|
-
// Frontend
|
|
142
|
-
frontendUrl?: string // Password reset link base URL
|
|
143
|
-
appName?: string // Security email brand (default: 'Your app')
|
|
141
|
+
// Frontend
|
|
142
|
+
frontendUrl?: string // Password reset link base URL
|
|
144
143
|
|
|
145
144
|
// Login identifier normalization (see "Identity presets")
|
|
146
145
|
identity?: {
|
|
@@ -875,6 +874,13 @@ the successful Next.js render receives. Attempts to override `cookie` or
|
|
|
875
874
|
`authorization` fail closed; only Najm's validated recovery path may replace
|
|
876
875
|
the cookie after it authorizes the recovered session.
|
|
877
876
|
|
|
877
|
+
Speculative/prefetch requests (`next-router-prefetch`, `purpose: prefetch`,
|
|
878
|
+
`sec-purpose` containing `prefetch`, `next-router-state-tree` metadata-only)
|
|
879
|
+
receive the same treatment as direct navigation: a valid signed snapshot or
|
|
880
|
+
non-rotating `/session/recover` validation is still required. Refresh-cookie
|
|
881
|
+
presence is never authorization, so do not bypass `auth.proxy` when a refresh
|
|
882
|
+
cookie is present on a prefetch. Recovery never rotates refresh tokens.
|
|
883
|
+
|
|
878
884
|
```typescript
|
|
879
885
|
// src/app/api/[...route]/route.ts
|
|
880
886
|
import { handle } from 'najm-core';
|
|
@@ -1131,16 +1137,10 @@ consumption. Once consumed, a token stays consumed even if the later user
|
|
|
1131
1137
|
mutation fails; restoring it would make the link replayable, so the user must
|
|
1132
1138
|
request a new one.
|
|
1133
1139
|
|
|
1134
|
-
Accepting an account invitation also marks the destination email verified and
|
|
1135
|
-
activates the account when its status is `pending`. An ordinary password reset
|
|
1136
|
-
changes neither verification nor lifecycle status, and an explicitly inactive
|
|
1137
|
-
invited account remains inactive.
|
|
1138
|
-
|
|
1139
|
-
Set `appName` on `auth()` to brand the invitation subject and email card. The
|
|
1140
|
-
provisioned role is presented as the account type, so a sponsor invitation can
|
|
1141
|
-
say “Activate your sponsor account” without application-owned HTML. The shared
|
|
1142
|
-
template uses inline critical styles for Gmail and keeps the raw token URL out
|
|
1143
|
-
of visible fallback copy.
|
|
1140
|
+
Accepting an account invitation also marks the destination email verified and
|
|
1141
|
+
activates the account when its status is `pending`. An ordinary password reset
|
|
1142
|
+
changes neither verification nor lifecycle status, and an explicitly inactive
|
|
1143
|
+
invited account remains inactive.
|
|
1144
1144
|
|
|
1145
1145
|
The built-in memory and Redis drivers implement the required atomic primitive.
|
|
1146
1146
|
A custom cache driver may omit `compareAndDelete()` for compatibility with
|
package/dist/index.d.ts
CHANGED
|
@@ -198,8 +198,6 @@ interface AuthConfig {
|
|
|
198
198
|
defaultRole: string | null;
|
|
199
199
|
/** Frontend URL for password reset links (default: 'http://localhost:3000') */
|
|
200
200
|
frontendUrl: string;
|
|
201
|
-
/** Product name used in security email subjects and templates. */
|
|
202
|
-
appName: string;
|
|
203
201
|
/** Registration mode: 'active' auto-activates, 'pending' requires admin approval (default: 'active') */
|
|
204
202
|
registrationMode: 'active' | 'pending';
|
|
205
203
|
/** Whether the unauthenticated POST /auth/register route is mounted. */
|
|
@@ -267,8 +265,6 @@ type AuthPluginConfig = {
|
|
|
267
265
|
defaultRole?: string | null;
|
|
268
266
|
/** Frontend URL for password reset links. Falls back to FRONTEND_URL env var, then 'http://localhost:3000' */
|
|
269
267
|
frontendUrl?: string;
|
|
270
|
-
/** Product name used in account invitation emails (default: 'Your app'). */
|
|
271
|
-
appName?: string;
|
|
272
268
|
/** Registration mode: 'active' auto-activates new users, 'pending' requires admin approval (default: 'active') */
|
|
273
269
|
registrationMode?: 'active' | 'pending';
|
|
274
270
|
/**
|
|
@@ -436,7 +432,7 @@ var auth = {
|
|
|
436
432
|
subject: "Reset your password"
|
|
437
433
|
},
|
|
438
434
|
accountInvite: {
|
|
439
|
-
subject: "
|
|
435
|
+
subject: "You've been invited — set up your account"
|
|
440
436
|
}
|
|
441
437
|
}
|
|
442
438
|
};
|
package/dist/index.js
CHANGED
|
@@ -2212,7 +2212,7 @@ var TokenService = class TokenService2 {
|
|
|
2212
2212
|
}
|
|
2213
2213
|
rejectRefreshSession(messageKey = "errors.refreshTokenInvalid") {
|
|
2214
2214
|
this.clearRefreshSessionCookies();
|
|
2215
|
-
Err7(this.t(messageKey), 401);
|
|
2215
|
+
return Err7(this.t(messageKey), 401);
|
|
2216
2216
|
}
|
|
2217
2217
|
async assertRefreshFamilyAllowed(tokenFamily, userId) {
|
|
2218
2218
|
if (await this.invalidation.familyStatus(tokenFamily, userId) === "revoked") {
|
|
@@ -3488,16 +3488,9 @@ var AuthService = class AuthService2 {
|
|
|
3488
3488
|
});
|
|
3489
3489
|
const { token } = await this.tokenService.generateInviteToken(user.id);
|
|
3490
3490
|
const inviteLink = `${this.config.frontendUrl}/reset-password?token=${token}`;
|
|
3491
|
-
const accountType = body.role?.trim().toLowerCase();
|
|
3492
|
-
const accountLabel = accountType ? `${accountType} account` : "account";
|
|
3493
3491
|
let emailSent = false;
|
|
3494
3492
|
try {
|
|
3495
|
-
await this.emailService.sendHtml(body.email, this.t("emails.accountInvite.subject", {
|
|
3496
|
-
accountLabel,
|
|
3497
|
-
appName: this.config.appName
|
|
3498
|
-
}), accountInviteTemplate({
|
|
3499
|
-
accountType,
|
|
3500
|
-
appName: this.config.appName,
|
|
3493
|
+
await this.emailService.sendHtml(body.email, this.t("emails.accountInvite.subject"), accountInviteTemplate({
|
|
3501
3494
|
inviteLink,
|
|
3502
3495
|
userName: user.name || body.email
|
|
3503
3496
|
}));
|
|
@@ -6353,7 +6346,7 @@ var en_default = {
|
|
|
6353
6346
|
subject: "Reset your password"
|
|
6354
6347
|
},
|
|
6355
6348
|
accountInvite: {
|
|
6356
|
-
subject: "
|
|
6349
|
+
subject: "You've been invited \u2014 set up your account"
|
|
6357
6350
|
}
|
|
6358
6351
|
}
|
|
6359
6352
|
},
|
|
@@ -7485,13 +7478,6 @@ var validateCallbackUrl = /* @__PURE__ */ __name((value, name) => {
|
|
|
7485
7478
|
}
|
|
7486
7479
|
return callback.toString();
|
|
7487
7480
|
}, "validateCallbackUrl");
|
|
7488
|
-
var resolveAppName = /* @__PURE__ */ __name((value) => {
|
|
7489
|
-
const appName = value?.trim() || "Your app";
|
|
7490
|
-
if (appName.length > 80 || /[\u0000-\u001f\u007f]/.test(appName)) {
|
|
7491
|
-
throw new Error("auth.appName must be at most 80 characters without control characters");
|
|
7492
|
-
}
|
|
7493
|
-
return appName;
|
|
7494
|
-
}, "resolveAppName");
|
|
7495
7481
|
var resolveGoogleConfig = /* @__PURE__ */ __name((config) => {
|
|
7496
7482
|
const configuredGoogle = config?.oauth?.google;
|
|
7497
7483
|
if (!configuredGoogle)
|
|
@@ -7568,7 +7554,6 @@ var resolveAuthConfig = /* @__PURE__ */ __name((config) => {
|
|
|
7568
7554
|
blacklistPrefix: config?.blacklistPrefix ?? "auth:blacklist:",
|
|
7569
7555
|
defaultRole: config?.defaultRole ?? null,
|
|
7570
7556
|
frontendUrl: config?.frontendUrl ?? process.env.FRONTEND_URL ?? "http://localhost:3000",
|
|
7571
|
-
appName: resolveAppName(config?.appName),
|
|
7572
7557
|
registrationMode: config?.registrationMode ?? "active",
|
|
7573
7558
|
publicRegistration: config?.publicRegistration ?? true,
|
|
7574
7559
|
requireVerifiedEmail: config?.requireVerifiedEmail ?? false,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "najm-auth",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.3",
|
|
4
4
|
"description": "Authentication and authorization library for najm framework",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -97,7 +97,7 @@
|
|
|
97
97
|
"najm-guard": "^2.0.2",
|
|
98
98
|
"najm-i18n": "^2.1.2",
|
|
99
99
|
"najm-cache": "^2.2.0",
|
|
100
|
-
"najm-email": "^2.0.
|
|
100
|
+
"najm-email": "^2.0.3",
|
|
101
101
|
"najm-rate": "^2.1.1",
|
|
102
102
|
"najm-validation": "^2.0.2",
|
|
103
103
|
"jsonwebtoken": "^9.0.3",
|