@thinkingcat/auth-utils 1.0.38 → 1.0.40
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/dist/index.js +47 -56
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -211,36 +211,49 @@ function createNextAuthJWT(payload, serviceId) {
|
|
|
211
211
|
* @returns 인코딩된 세션 토큰
|
|
212
212
|
*/
|
|
213
213
|
async function encodeNextAuthToken(jwt, secret, maxAge = 30 * 24 * 60 * 60) {
|
|
214
|
-
//
|
|
215
|
-
// next-auth/jwt의 encode 대신 jose를 직접 사용
|
|
216
|
-
// (Edge Runtime에서 encode한 토큰을 Node.js Runtime에서 decode 못하는 문제 방지)
|
|
217
|
-
debugLog('encodeNextAuthToken', 'Using jose EncryptJWT for cross-runtime compatibility');
|
|
218
|
-
// NextAuth는 secret을 SHA-256 해시하여 32바이트 키로 사용
|
|
219
|
-
const secretHash = await createHashSHA256(secret);
|
|
220
|
-
// SHA-256 해시는 64자 hex 문자열이므로, 32바이트로 변환
|
|
221
|
-
const keyBytes = new Uint8Array(32);
|
|
222
|
-
for (let i = 0; i < 32; i++) {
|
|
223
|
-
keyBytes[i] = parseInt(secretHash.slice(i * 2, i * 2 + 2), 16);
|
|
224
|
-
}
|
|
225
|
-
const now = Math.floor(Date.now() / 1000);
|
|
226
|
-
// EncryptJWT를 사용하여 JWE 토큰 생성
|
|
227
|
-
// NextAuth는 'dir' 키 관리와 'A256GCM' 암호화를 사용
|
|
214
|
+
// NextAuth의 encode() 함수를 우선적으로 사용 (가장 호환성 좋음)
|
|
228
215
|
try {
|
|
229
|
-
const
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
debugLog('encodeNextAuthToken', 'EncryptJWT successful, length:', token.length);
|
|
239
|
-
return token;
|
|
216
|
+
const { encode } = await Promise.resolve().then(() => __importStar(require('next-auth/jwt')));
|
|
217
|
+
debugLog('encodeNextAuthToken', 'Using next-auth/jwt encode');
|
|
218
|
+
const encoded = await encode({
|
|
219
|
+
token: jwt,
|
|
220
|
+
secret: secret,
|
|
221
|
+
maxAge: maxAge,
|
|
222
|
+
});
|
|
223
|
+
debugLog('encodeNextAuthToken', 'NextAuth encode successful, length:', encoded.length);
|
|
224
|
+
return encoded;
|
|
240
225
|
}
|
|
241
226
|
catch (error) {
|
|
242
|
-
|
|
243
|
-
|
|
227
|
+
// Edge Runtime에서 encode가 작동하지 않을 수 있으므로
|
|
228
|
+
// jose의 EncryptJWT를 fallback으로 사용
|
|
229
|
+
debugLog('encodeNextAuthToken', 'NextAuth encode failed, using jose EncryptJWT fallback', error);
|
|
230
|
+
// NextAuth는 secret을 SHA-256 해시하여 32바이트 키로 사용
|
|
231
|
+
const secretHash = await createHashSHA256(secret);
|
|
232
|
+
// SHA-256 해시는 64자 hex 문자열이므로, 32바이트로 변환
|
|
233
|
+
const keyBytes = new Uint8Array(32);
|
|
234
|
+
for (let i = 0; i < 32; i++) {
|
|
235
|
+
keyBytes[i] = parseInt(secretHash.slice(i * 2, i * 2 + 2), 16);
|
|
236
|
+
}
|
|
237
|
+
const now = Math.floor(Date.now() / 1000);
|
|
238
|
+
// EncryptJWT를 사용하여 JWE 토큰 생성
|
|
239
|
+
// NextAuth는 'dir' 키 관리와 'A256GCM' 암호화를 사용
|
|
240
|
+
try {
|
|
241
|
+
const token = await new jose_1.EncryptJWT(jwt)
|
|
242
|
+
.setProtectedHeader({
|
|
243
|
+
alg: 'dir', // Direct key agreement
|
|
244
|
+
enc: 'A256GCM' // AES-256-GCM encryption
|
|
245
|
+
})
|
|
246
|
+
.setIssuedAt(now)
|
|
247
|
+
.setExpirationTime(now + maxAge)
|
|
248
|
+
.setJti(crypto.randomUUID())
|
|
249
|
+
.encrypt(keyBytes);
|
|
250
|
+
debugLog('encodeNextAuthToken', 'EncryptJWT fallback successful, length:', token.length);
|
|
251
|
+
return token;
|
|
252
|
+
}
|
|
253
|
+
catch (encryptError) {
|
|
254
|
+
debugError('encodeNextAuthToken', 'EncryptJWT also failed:', encryptError);
|
|
255
|
+
throw new Error(`Failed to encode NextAuth token: ${error instanceof Error ? error.message : String(error)}`);
|
|
256
|
+
}
|
|
244
257
|
}
|
|
245
258
|
}
|
|
246
259
|
function setCustomTokens(response, accessToken, optionsOrRefreshToken, options) {
|
|
@@ -435,44 +448,22 @@ async function createAuthResponse(accessToken, secret, options) {
|
|
|
435
448
|
}
|
|
436
449
|
// accessTokenExpires 추가 (15분)
|
|
437
450
|
jwt.accessTokenExpires = Date.now() + (15 * 60 * 1000);
|
|
438
|
-
debugLog('createAuthResponse', 'JWT
|
|
451
|
+
debugLog('createAuthResponse', 'JWT prepared (NextAuth will create session from custom tokens):', {
|
|
439
452
|
hasId: !!jwt.id,
|
|
440
453
|
hasEmail: !!jwt.email,
|
|
441
454
|
hasRole: !!jwt.role,
|
|
442
455
|
hasRefreshToken: !!jwt.refreshToken,
|
|
443
456
|
});
|
|
444
|
-
// 3.
|
|
445
|
-
const nextAuthToken = await encodeNextAuthToken(jwt, secret);
|
|
446
|
-
debugLog('createAuthResponse', 'NextAuth session token encoded:', {
|
|
447
|
-
tokenLength: nextAuthToken.length,
|
|
448
|
-
});
|
|
449
|
-
// 4. Response 생성 (HTTP 302 리다이렉트 사용)
|
|
457
|
+
// 3. Response 생성 (HTTP 302 리다이렉트 사용)
|
|
450
458
|
const { NextResponse: NextResponseClass } = await getNextServer();
|
|
451
459
|
// redirectPath가 있으면 302 리다이렉트, 없으면 200 OK
|
|
452
460
|
const response = redirectPath
|
|
453
461
|
? NextResponseClass.redirect(new URL(redirectPath, req.url), { status: 302 })
|
|
454
462
|
: NextResponseClass.json({ success: true, message: text || 'Authentication successful' }, { status: 200 });
|
|
455
|
-
//
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
const cookieOptions = {
|
|
460
|
-
httpOnly: true,
|
|
461
|
-
secure: isProduction,
|
|
462
|
-
sameSite: isProduction ? 'none' : 'lax',
|
|
463
|
-
path: '/',
|
|
464
|
-
maxAge: 30 * 24 * 60 * 60, // 30일
|
|
465
|
-
};
|
|
466
|
-
if (cookieDomain) {
|
|
467
|
-
cookieOptions.domain = cookieDomain;
|
|
468
|
-
}
|
|
469
|
-
response.cookies.set(nextAuthCookieName, nextAuthToken, cookieOptions);
|
|
470
|
-
debugLog('createAuthResponse', 'NextAuth session cookie set:', {
|
|
471
|
-
name: nextAuthCookieName,
|
|
472
|
-
valueLength: nextAuthToken.length,
|
|
473
|
-
...cookieOptions,
|
|
474
|
-
});
|
|
475
|
-
// 6. 커스텀 토큰 쿠키 설정
|
|
463
|
+
// 4. 처음 로그인 시에는 NextAuth 쿠키를 생성하지 않음
|
|
464
|
+
// Edge Runtime에서 생성한 NextAuth 쿠키는 Node.js Runtime에서 디코드 실패
|
|
465
|
+
// 대신 커스텀 토큰만 설정하고, handleJWTCallback이 이를 읽어서 세션 생성
|
|
466
|
+
// 5. 커스텀 토큰 쿠키 설정
|
|
476
467
|
if (refreshToken) {
|
|
477
468
|
setCustomTokens(response, accessToken, refreshToken, {
|
|
478
469
|
cookiePrefix,
|
|
@@ -647,7 +638,7 @@ async function verifyAndRefreshToken(req, secret, options) {
|
|
|
647
638
|
jwt.refreshToken = newRefreshToken;
|
|
648
639
|
}
|
|
649
640
|
jwt.accessTokenExpires = Date.now() + (15 * 60 * 1000);
|
|
650
|
-
// NextAuth 세션 쿠키 생성 (
|
|
641
|
+
// NextAuth 세션 쿠키 생성 (NextAuth encode() 우선 사용)
|
|
651
642
|
try {
|
|
652
643
|
const nextAuthToken = await encodeNextAuthToken(jwt, secret);
|
|
653
644
|
const nextAuthCookieName = isProduction
|
package/package.json
CHANGED