najm-auth 4.0.2 → 4.0.4
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 +27 -9
- package/dist/index.d.ts +14 -0
- package/dist/index.js +28 -11
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -138,9 +138,15 @@ auth({
|
|
|
138
138
|
publicRegistration?: boolean // Default: true; mounts POST /auth/register
|
|
139
139
|
bcryptRounds?: number // Default: 10 (valid: 4-31)
|
|
140
140
|
|
|
141
|
-
// Frontend
|
|
141
|
+
// Frontend
|
|
142
142
|
frontendUrl?: string // Password reset link base URL
|
|
143
143
|
appName?: string // Security email brand (default: 'Your app')
|
|
144
|
+
accountInviteLogo?: { // Optional CID-backed inline mark
|
|
145
|
+
alt?: string
|
|
146
|
+
contentBase64: string
|
|
147
|
+
contentType: string
|
|
148
|
+
filename: string
|
|
149
|
+
}
|
|
144
150
|
|
|
145
151
|
// Login identifier normalization (see "Identity presets")
|
|
146
152
|
identity?: {
|
|
@@ -875,6 +881,13 @@ the successful Next.js render receives. Attempts to override `cookie` or
|
|
|
875
881
|
`authorization` fail closed; only Najm's validated recovery path may replace
|
|
876
882
|
the cookie after it authorizes the recovered session.
|
|
877
883
|
|
|
884
|
+
Speculative/prefetch requests (`next-router-prefetch`, `purpose: prefetch`,
|
|
885
|
+
`sec-purpose` containing `prefetch`, `next-router-state-tree` metadata-only)
|
|
886
|
+
receive the same treatment as direct navigation: a valid signed snapshot or
|
|
887
|
+
non-rotating `/session/recover` validation is still required. Refresh-cookie
|
|
888
|
+
presence is never authorization, so do not bypass `auth.proxy` when a refresh
|
|
889
|
+
cookie is present on a prefetch. Recovery never rotates refresh tokens.
|
|
890
|
+
|
|
878
891
|
```typescript
|
|
879
892
|
// src/app/api/[...route]/route.ts
|
|
880
893
|
import { handle } from 'najm-core';
|
|
@@ -1131,16 +1144,21 @@ consumption. Once consumed, a token stays consumed even if the later user
|
|
|
1131
1144
|
mutation fails; restoring it would make the link replayable, so the user must
|
|
1132
1145
|
request a new one.
|
|
1133
1146
|
|
|
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
|
|
1147
|
+
Accepting an account invitation also marks the destination email verified and
|
|
1148
|
+
activates the account when its status is `pending`. An ordinary password reset
|
|
1149
|
+
changes neither verification nor lifecycle status, and an explicitly inactive
|
|
1150
|
+
invited account remains inactive.
|
|
1151
|
+
|
|
1152
|
+
Set `appName` on `auth()` to brand the invitation subject and email card. The
|
|
1153
|
+
provisioned role is presented as the account type, so a sponsor invitation can
|
|
1154
|
+
say “Activate your sponsor account” without application-owned HTML. The shared
|
|
1142
1155
|
template uses inline critical styles for Gmail and keeps the raw token URL out
|
|
1143
1156
|
of visible fallback copy.
|
|
1157
|
+
|
|
1158
|
+
For a branded mark that works in email clients without a public asset URL, set
|
|
1159
|
+
`accountInviteLogo` to base64 content plus its MIME type and filename. Najm
|
|
1160
|
+
attaches it inline and points the shared template at a stable CID; when omitted,
|
|
1161
|
+
the template renders `appName` as text.
|
|
1144
1162
|
|
|
1145
1163
|
The built-in memory and Redis drivers implement the required atomic primitive.
|
|
1146
1164
|
A custom cache driver may omit `compareAndDelete()` for compatibility with
|
package/dist/index.d.ts
CHANGED
|
@@ -200,6 +200,13 @@ interface AuthConfig {
|
|
|
200
200
|
frontendUrl: string;
|
|
201
201
|
/** Product name used in security email subjects and templates. */
|
|
202
202
|
appName: string;
|
|
203
|
+
/** Optional inline logo embedded in account invitation emails. */
|
|
204
|
+
accountInviteLogo?: {
|
|
205
|
+
alt?: string;
|
|
206
|
+
contentBase64: string;
|
|
207
|
+
contentType: string;
|
|
208
|
+
filename: string;
|
|
209
|
+
};
|
|
203
210
|
/** Registration mode: 'active' auto-activates, 'pending' requires admin approval (default: 'active') */
|
|
204
211
|
registrationMode: 'active' | 'pending';
|
|
205
212
|
/** Whether the unauthenticated POST /auth/register route is mounted. */
|
|
@@ -269,6 +276,13 @@ type AuthPluginConfig = {
|
|
|
269
276
|
frontendUrl?: string;
|
|
270
277
|
/** Product name used in account invitation emails (default: 'Your app'). */
|
|
271
278
|
appName?: string;
|
|
279
|
+
/** Optional inline logo embedded in account invitation emails. */
|
|
280
|
+
accountInviteLogo?: {
|
|
281
|
+
alt?: string;
|
|
282
|
+
contentBase64: string;
|
|
283
|
+
contentType: string;
|
|
284
|
+
filename: string;
|
|
285
|
+
};
|
|
272
286
|
/** Registration mode: 'active' auto-activates new users, 'pending' requires admin approval (default: 'active') */
|
|
273
287
|
registrationMode?: 'active' | 'pending';
|
|
274
288
|
/**
|
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") {
|
|
@@ -3492,16 +3492,32 @@ var AuthService = class AuthService2 {
|
|
|
3492
3492
|
const accountLabel = accountType ? `${accountType} account` : "account";
|
|
3493
3493
|
let emailSent = false;
|
|
3494
3494
|
try {
|
|
3495
|
-
|
|
3496
|
-
|
|
3497
|
-
|
|
3498
|
-
|
|
3499
|
-
|
|
3500
|
-
|
|
3501
|
-
|
|
3502
|
-
|
|
3503
|
-
|
|
3504
|
-
|
|
3495
|
+
const logo = this.config.accountInviteLogo;
|
|
3496
|
+
const logoCid = logo ? "najm-account-invite-logo" : void 0;
|
|
3497
|
+
const result = await this.emailService.send({
|
|
3498
|
+
to: body.email,
|
|
3499
|
+
subject: this.t("emails.accountInvite.subject", {
|
|
3500
|
+
accountLabel,
|
|
3501
|
+
appName: this.config.appName
|
|
3502
|
+
}),
|
|
3503
|
+
html: accountInviteTemplate({
|
|
3504
|
+
accountType,
|
|
3505
|
+
appName: this.config.appName,
|
|
3506
|
+
inviteLink,
|
|
3507
|
+
logoAlt: logo?.alt,
|
|
3508
|
+
logoSrc: logoCid ? `cid:${logoCid}` : void 0,
|
|
3509
|
+
userName: user.name || body.email
|
|
3510
|
+
}),
|
|
3511
|
+
attachments: logo ? [{
|
|
3512
|
+
filename: logo.filename,
|
|
3513
|
+
content: logo.contentBase64,
|
|
3514
|
+
contentType: logo.contentType,
|
|
3515
|
+
cid: logoCid,
|
|
3516
|
+
disposition: "inline",
|
|
3517
|
+
encoding: "base64"
|
|
3518
|
+
}] : void 0
|
|
3519
|
+
});
|
|
3520
|
+
emailSent = result.success;
|
|
3505
3521
|
} catch (error) {
|
|
3506
3522
|
this.logger.warn("Account invite email failed", { email: body.email, error });
|
|
3507
3523
|
}
|
|
@@ -7569,6 +7585,7 @@ var resolveAuthConfig = /* @__PURE__ */ __name((config) => {
|
|
|
7569
7585
|
defaultRole: config?.defaultRole ?? null,
|
|
7570
7586
|
frontendUrl: config?.frontendUrl ?? process.env.FRONTEND_URL ?? "http://localhost:3000",
|
|
7571
7587
|
appName: resolveAppName(config?.appName),
|
|
7588
|
+
accountInviteLogo: config?.accountInviteLogo,
|
|
7572
7589
|
registrationMode: config?.registrationMode ?? "active",
|
|
7573
7590
|
publicRegistration: config?.publicRegistration ?? true,
|
|
7574
7591
|
requireVerifiedEmail: config?.requireVerifiedEmail ?? false,
|