@spfn/auth 0.2.0-beta.83 → 0.2.0-beta.84
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 +7 -4
- package/dist/server.js +29 -2
- package/dist/server.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -268,10 +268,13 @@ no Google account is linked or no refresh token is available).
|
|
|
268
268
|
Kakao's `is_email_valid` and `is_email_verified` claims are both required before its email can
|
|
269
269
|
link an existing SPFN account. GitHub uses the primary email from `/user/emails` (needs the
|
|
270
270
|
`user:email` scope) and treats it as verified only when GitHub marks it verified; without that
|
|
271
|
-
scope it falls back to the public profile email, unverified. Naver
|
|
272
|
-
Naver
|
|
273
|
-
|
|
274
|
-
|
|
271
|
+
scope it falls back to the public profile email, unverified. Naver's profile email is either the
|
|
272
|
+
Naver account email or a contact email that passed Naver's own verification, so a present email
|
|
273
|
+
is treated as verified — it is stored on the user row and may link an existing account by email,
|
|
274
|
+
the same trust level as Kakao. Accounts created before this policy (user row with `email` null)
|
|
275
|
+
are backfilled on their next login: if the provider reports a verified email and no other account
|
|
276
|
+
owns it, `email` and `emailVerifiedAt` are filled in (best-effort; a conflict skips the backfill
|
|
277
|
+
and the login continues).
|
|
275
278
|
|
|
276
279
|
### Provider-initiated unlink notifications (`unlink-notify`)
|
|
277
280
|
|
package/dist/server.js
CHANGED
|
@@ -10097,8 +10097,9 @@ var naverProvider = {
|
|
|
10097
10097
|
return {
|
|
10098
10098
|
providerUserId: profile.id,
|
|
10099
10099
|
email: typeof profile.email === "string" ? profile.email : null,
|
|
10100
|
-
//
|
|
10101
|
-
|
|
10100
|
+
// 네이버 프로필 이메일은 네이버 계정 이메일이거나 인증 절차를 거친 연락처
|
|
10101
|
+
// 이메일이다 — 존재하면 검증된 것으로 취급한다(카카오와 같은 신뢰 수준).
|
|
10102
|
+
emailVerified: typeof profile.email === "string",
|
|
10102
10103
|
name: typeof profile.name === "string" ? profile.name : typeof profile.nickname === "string" ? profile.nickname : void 0,
|
|
10103
10104
|
avatar: typeof profile.profile_image === "string" ? profile.profile_image : void 0
|
|
10104
10105
|
};
|
|
@@ -10223,6 +10224,7 @@ async function oauthCallbackService(params) {
|
|
|
10223
10224
|
refreshToken: tokens.refreshToken ?? existingSocialAccount.refreshToken,
|
|
10224
10225
|
tokenExpiresAt: tokenExpiryDate(tokens.expiresIn)
|
|
10225
10226
|
});
|
|
10227
|
+
await backfillVerifiedEmail(userId, identity);
|
|
10226
10228
|
} else {
|
|
10227
10229
|
const result = await createOrLinkUser(provider, identity, tokens, stateData.metadata);
|
|
10228
10230
|
userId = result.userId;
|
|
@@ -10280,6 +10282,30 @@ async function assertActiveForOAuthSession(userId) {
|
|
|
10280
10282
|
}
|
|
10281
10283
|
throw new AccountDisabledError2({ status: user.status });
|
|
10282
10284
|
}
|
|
10285
|
+
async function backfillVerifiedEmail(userId, identity) {
|
|
10286
|
+
if (!identity.email || !identity.emailVerified) {
|
|
10287
|
+
return;
|
|
10288
|
+
}
|
|
10289
|
+
const user = await usersRepository.findById(userId);
|
|
10290
|
+
if (!user || user.email) {
|
|
10291
|
+
return;
|
|
10292
|
+
}
|
|
10293
|
+
const emailOwner = await usersRepository.findByEmail(identity.email);
|
|
10294
|
+
if (emailOwner && emailOwner.id !== userId) {
|
|
10295
|
+
return;
|
|
10296
|
+
}
|
|
10297
|
+
try {
|
|
10298
|
+
await usersRepository.updateById(userId, {
|
|
10299
|
+
email: identity.email,
|
|
10300
|
+
emailVerifiedAt: /* @__PURE__ */ new Date()
|
|
10301
|
+
});
|
|
10302
|
+
} catch (error) {
|
|
10303
|
+
authLogger.service.warn("Verified-email backfill failed; continuing login", {
|
|
10304
|
+
userId: String(userId),
|
|
10305
|
+
error: error instanceof Error ? error.message : String(error)
|
|
10306
|
+
});
|
|
10307
|
+
}
|
|
10308
|
+
}
|
|
10283
10309
|
async function createOrLinkUser(provider, identity, tokens, metadata) {
|
|
10284
10310
|
const existingUser = identity.email ? await usersRepository.findByEmail(identity.email) : null;
|
|
10285
10311
|
let userId;
|
|
@@ -10425,6 +10451,7 @@ async function persistNativeLogin(identity, params) {
|
|
|
10425
10451
|
let isNewUser = false;
|
|
10426
10452
|
if (existing) {
|
|
10427
10453
|
userId = existing.userId;
|
|
10454
|
+
await backfillVerifiedEmail(userId, identity);
|
|
10428
10455
|
} else {
|
|
10429
10456
|
const result = await createOrLinkUser(params.provider, identity, void 0, params.metadata);
|
|
10430
10457
|
userId = result.userId;
|