@thinkingcat/auth-utils 1.0.21 → 1.0.23

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.
Files changed (2) hide show
  1. package/dist/index.js +66 -28
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -419,14 +419,21 @@ async function createAuthResponse(accessToken, secret, options) {
419
419
  const { payload } = tokenResult;
420
420
  // 2. NextAuth JWT 생성
421
421
  const jwt = createNextAuthJWT(payload, serviceId);
422
+ // refreshToken 추가
423
+ if (refreshToken) {
424
+ jwt.refreshToken = refreshToken;
425
+ }
426
+ // accessTokenExpires 추가 (15분)
427
+ jwt.accessTokenExpires = Date.now() + (15 * 60 * 1000);
422
428
  debugLog('createAuthResponse', 'JWT created:', {
423
429
  hasId: !!jwt.id,
424
430
  hasEmail: !!jwt.email,
425
431
  hasRole: !!jwt.role,
432
+ hasRefreshToken: !!jwt.refreshToken,
426
433
  });
427
- // 3. NextAuth 세션 토큰 생성 전략
428
- // NextAuth의 JWT 콜백이 custom tokens를 읽어서 자동으로 NextAuth 세션을 생성
429
- debugLog('createAuthResponse', 'Custom tokens will be set, NextAuth JWT callback will handle session creation');
434
+ // 3. NextAuth session cookie 생성
435
+ const nextAuthToken = await encodeNextAuthToken(jwt, secret);
436
+ debugLog('createAuthResponse', 'NextAuth session token encoded');
430
437
  // 5. HTML 생성
431
438
  const displayText = text || serviceId;
432
439
  const html = redirectPath
@@ -440,7 +447,23 @@ async function createAuthResponse(accessToken, secret, options) {
440
447
  'Content-Type': 'text/html',
441
448
  },
442
449
  });
443
- // 4. 쿠키 설정
450
+ // 4. NextAuth session cookie 설정
451
+ const nextAuthCookieName = isProduction
452
+ ? '__Secure-next-auth.session-token'
453
+ : 'next-auth.session-token';
454
+ const cookieOptions = {
455
+ httpOnly: true,
456
+ secure: isProduction,
457
+ sameSite: isProduction ? 'none' : 'lax',
458
+ path: '/',
459
+ maxAge: 30 * 24 * 60 * 60, // 30일
460
+ };
461
+ if (cookieDomain) {
462
+ cookieOptions.domain = cookieDomain;
463
+ }
464
+ response.cookies.set(nextAuthCookieName, nextAuthToken, cookieOptions);
465
+ debugLog('createAuthResponse', 'NextAuth session cookie set:', nextAuthCookieName);
466
+ // 5. 커스텀 토큰 쿠키 설정
444
467
  if (refreshToken) {
445
468
  setCustomTokens(response, accessToken, refreshToken, {
446
469
  cookiePrefix,
@@ -886,22 +909,44 @@ async function handleJWTCallback(token, user, account, options) {
886
909
  debugLog('handleJWTCallback', 'Initial login, creating token from user data');
887
910
  return createInitialJWTToken(token, user, account);
888
911
  }
889
- // 2. 토큰 유효성 체크
912
+ // 2. 커스텀 토큰 쿠키 우선 체크 (middleware에서 refresh한 토큰이 있을 수 있음)
913
+ if (secret && licenseKey && serviceId) {
914
+ const cookieNameToUse = cookieName || `${serviceId}_access_token`;
915
+ debugLog('handleJWTCallback', 'Checking custom token cookie first:', cookieNameToUse);
916
+ const customJwt = await getJWTFromCustomTokenCookie(cookieNameToUse, secret, serviceId, licenseKey);
917
+ if (customJwt) {
918
+ debugLog('handleJWTCallback', 'Found valid custom token cookie, using it');
919
+ // refreshToken이 있으면 유지
920
+ if (token.refreshToken) {
921
+ customJwt.refreshToken = token.refreshToken;
922
+ }
923
+ return customJwt;
924
+ }
925
+ debugLog('handleJWTCallback', 'No valid custom token cookie found');
926
+ }
927
+ // 3. 토큰 유효성 체크
890
928
  const now = Date.now();
891
929
  const expires = token.accessTokenExpires;
892
930
  const hasValidToken = token.id && expires && expires > now;
893
931
  const refreshToken = token.refreshToken;
894
- // 2-1. nextauth token이 있고 만료되지 않았으면 그대로 사용
932
+ debugLog('handleJWTCallback', 'Token status:', {
933
+ hasId: !!token.id,
934
+ hasExpires: !!expires,
935
+ expiresIn: expires ? Math.round((expires - now) / 1000) + 's' : 'N/A',
936
+ hasValidToken,
937
+ hasRefreshToken: !!refreshToken,
938
+ });
939
+ // 3-1. nextauth token이 있고 만료되지 않았으면 그대로 사용
895
940
  if (hasValidToken) {
896
941
  debugLog('handleJWTCallback', 'Token is still valid, using existing token');
897
942
  return token;
898
943
  }
899
- // 2-2. nextauth token이 없거나 만료됨 → refresh token으로 갱신 시도
944
+ // 3-2. nextauth token이 없거나 만료됨 → refresh token으로 갱신 시도
900
945
  // (refreshToken이 있고 SSO 설정이 있을 때만)
901
946
  if (refreshToken && ssoBaseURL && authServiceKey && secret) {
902
- debugLog('handleJWTCallback', 'Token invalid or expired, attempting refresh');
947
+ debugLog('handleJWTCallback', 'Token invalid or expired, attempting SSO refresh');
903
948
  try {
904
- debugLog('handleJWTCallback', 'Calling SSO refresh endpoint');
949
+ debugLog('handleJWTCallback', 'Calling SSO refresh endpoint:', `${ssoBaseURL}/api/sso/refresh`);
905
950
  const response = await fetch(`${ssoBaseURL}/api/sso/refresh`, {
906
951
  method: 'POST',
907
952
  headers: {
@@ -910,10 +955,11 @@ async function handleJWTCallback(token, user, account, options) {
910
955
  },
911
956
  body: JSON.stringify({ refreshToken }),
912
957
  });
958
+ debugLog('handleJWTCallback', 'SSO refresh response status:', response.status);
913
959
  if (response.ok) {
914
960
  const result = await response.json();
915
961
  if (result.success && result.accessToken) {
916
- debugLog('handleJWTCallback', 'Successfully refreshed token');
962
+ debugLog('handleJWTCallback', 'Successfully refreshed token from SSO');
917
963
  // 새 액세스 토큰 검증 및 페이로드 추출
918
964
  const tokenResult = await verifyToken(result.accessToken, secret);
919
965
  if (tokenResult) {
@@ -926,35 +972,27 @@ async function handleJWTCallback(token, user, account, options) {
926
972
  }
927
973
  }
928
974
  }
929
- debugLog('handleJWTCallback', 'Failed to refresh token, SSO response not ok');
975
+ debugLog('handleJWTCallback', 'Failed to refresh token from SSO');
930
976
  }
931
977
  catch (error) {
932
978
  console.error('[handleJWTCallback] Error refreshing token:', error);
933
979
  }
934
980
  }
935
981
  else {
936
- debugLog('handleJWTCallback', 'Cannot refresh - missing refresh token or SSO config');
982
+ debugLog('handleJWTCallback', 'Cannot refresh - missing requirements:', {
983
+ hasRefreshToken: !!refreshToken,
984
+ hasSSO: !!ssoBaseURL,
985
+ hasAuthKey: !!authServiceKey,
986
+ hasSecret: !!secret,
987
+ });
937
988
  }
938
- // 3. refresh 실패 시 - 기존 토큰이 있으면 반환
989
+ // 4. refresh 실패 시 - 기존 토큰이 있으면 반환
939
990
  if (token.id) {
940
991
  debugLog('handleJWTCallback', 'Refresh failed, returning existing token (possibly expired)');
941
992
  return token;
942
993
  }
943
- // 4. 토큰에 id가 없는 경우 - 커스텀 토큰 쿠키에서 정보 읽기
944
- debugLog('handleJWTCallback', 'Token has no id, checking custom token cookie');
945
- if (secret && licenseKey && serviceId) {
946
- const cookieNameToUse = cookieName || `${serviceId}_access_token`;
947
- const jwt = await getJWTFromCustomTokenCookie(cookieNameToUse, secret, serviceId, licenseKey);
948
- if (jwt) {
949
- debugLog('handleJWTCallback', 'Successfully created JWT from custom token cookie');
950
- return jwt;
951
- }
952
- debugLog('handleJWTCallback', 'Failed to create JWT from custom token cookie');
953
- }
954
- else {
955
- debugLog('handleJWTCallback', 'Missing required parameters for custom token reading');
956
- }
957
- debugLog('handleJWTCallback', 'Returning original token');
994
+ // 5. 모든 시도 실패 - 토큰 반환
995
+ debugLog('handleJWTCallback', 'All attempts failed, returning empty token');
958
996
  return token;
959
997
  }
960
998
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thinkingcat/auth-utils",
3
- "version": "1.0.21",
3
+ "version": "1.0.23",
4
4
  "description": "Authentication utilities for ThinkingCat SSO services with conditional logging",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",