@spfn/auth 0.2.0-beta.61 → 0.2.0-beta.62

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.
@@ -1,7 +1,7 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { ReactNode } from 'react';
3
- import { S as SessionData } from '../session-Dbvz9Sdp.js';
4
- import { K as KeyAlgorithmType } from '../types-B1CzVZkU.js';
3
+ import { S as SessionData } from '../session-2CyIVxMY.js';
4
+ import { K as KeyAlgorithmType } from '../types-B4auHIax.js';
5
5
  import { NextRequest, NextResponse } from 'next/server';
6
6
 
7
7
  interface RequireAuthProps {
package/dist/server.d.ts CHANGED
@@ -1,14 +1,14 @@
1
- import { i as AuthInitOptions, d as VerificationPurpose, h as PermissionCategory, j as AuthContext } from './authenticate-B_HkYBzq.js';
2
- export { u as ChangePasswordParams, p as CheckAccountExistsParams, C as CheckAccountExistsResult, a1 as EmailSchema, I as IssueOneTimeTokenResult, s as LoginParams, L as LoginResult, t as LogoutParams, Z as OAuthCallbackParams, _ as OAuthCallbackResult, Y as OAuthStartParams, O as OAuthStartResult, a3 as PasswordSchema, a2 as PhoneSchema, q as RegisterParams, F as RegisterPublicKeyParams, a as RegisterResult, H as RevokeKeyParams, G as RotateKeyParams, b as RotateKeyResult, x as SendVerificationCodeParams, S as SendVerificationCodeResult, a4 as TargetTypeSchema, f as VERIFICATION_PURPOSES, e as VERIFICATION_TARGET_TYPES, a5 as VerificationPurposeSchema, V as VerificationTargetType, y as VerifyCodeParams, z as VerifyCodeResult, m as authRouter, $ as authenticate, Q as buildOAuthErrorUrl, o as changePasswordService, k as checkAccountExistsService, W as getEnabledOAuthProviders, X as getGoogleAccessToken, T as isOAuthProviderEnabled, J as issueOneTimeTokenService, l as loginService, n as logoutService, N as oauthCallbackService, M as oauthStartService, a0 as optionalAuth, B as registerPublicKeyService, r as registerService, E as revokeKeyService, D as rotateKeyService, v as sendVerificationCodeService, w as verifyCodeService, K as verifyOneTimeTokenService } from './authenticate-B_HkYBzq.js';
1
+ import { i as AuthInitOptions, d as VerificationPurpose, h as PermissionCategory, j as AuthContext } from './authenticate-DcOkuB7d.js';
2
+ export { u as ChangePasswordParams, p as CheckAccountExistsParams, C as CheckAccountExistsResult, a1 as EmailSchema, I as IssueOneTimeTokenResult, s as LoginParams, L as LoginResult, t as LogoutParams, Z as OAuthCallbackParams, _ as OAuthCallbackResult, Y as OAuthStartParams, O as OAuthStartResult, a3 as PasswordSchema, a2 as PhoneSchema, q as RegisterParams, F as RegisterPublicKeyParams, a as RegisterResult, H as RevokeKeyParams, G as RotateKeyParams, b as RotateKeyResult, x as SendVerificationCodeParams, S as SendVerificationCodeResult, a4 as TargetTypeSchema, f as VERIFICATION_PURPOSES, e as VERIFICATION_TARGET_TYPES, a5 as VerificationPurposeSchema, V as VerificationTargetType, y as VerifyCodeParams, z as VerifyCodeResult, m as authRouter, $ as authenticate, Q as buildOAuthErrorUrl, o as changePasswordService, k as checkAccountExistsService, W as getEnabledOAuthProviders, X as getGoogleAccessToken, T as isOAuthProviderEnabled, J as issueOneTimeTokenService, l as loginService, n as logoutService, N as oauthCallbackService, M as oauthStartService, a0 as optionalAuth, B as registerPublicKeyService, r as registerService, E as revokeKeyService, D as rotateKeyService, v as sendVerificationCodeService, w as verifyCodeService, K as verifyOneTimeTokenService } from './authenticate-DcOkuB7d.js';
3
3
  import * as drizzle_orm_pg_core from 'drizzle-orm/pg-core';
4
- import { K as KeyAlgorithmType, b as InvitationStatus, d as SocialProvider } from './types-B1CzVZkU.js';
5
- export { I as INVITATION_STATUSES, a as KEY_ALGORITHM, S as SOCIAL_PROVIDERS, U as USER_STATUSES, c as UserStatus } from './types-B1CzVZkU.js';
4
+ import { K as KeyAlgorithmType, b as InvitationStatus, d as SocialProvider } from './types-B4auHIax.js';
5
+ export { I as INVITATION_STATUSES, a as KEY_ALGORITHM, S as SOCIAL_PROVIDERS, U as USER_STATUSES, c as UserStatus } from './types-B4auHIax.js';
6
6
  import { UserProfile as UserProfile$1, ProfileInfo } from '@spfn/auth';
7
7
  import { BaseRepository } from '@spfn/core/db';
8
8
  import { Context } from 'hono';
9
9
  import * as _spfn_core_route from '@spfn/core/route';
10
10
  import { Algorithm } from 'jsonwebtoken';
11
- export { S as SessionData, g as getSessionInfo, s as sealSession, a as shouldRefreshSession, u as unsealSession } from './session-Dbvz9Sdp.js';
11
+ export { S as SessionData, g as getSessionInfo, s as sealSession, a as shouldRefreshSession, u as unsealSession } from './session-2CyIVxMY.js';
12
12
  import { SSETokenStore, SSETokenManager } from '@spfn/core/event/sse';
13
13
  import * as _spfn_core_logger from '@spfn/core/logger';
14
14
  import * as _spfn_core_event from '@spfn/core/event';
@@ -2063,14 +2063,14 @@ declare const userSocialAccounts: drizzle_orm_pg_core.PgTableWithColumns<{
2063
2063
  tableName: "user_social_accounts";
2064
2064
  dataType: "string";
2065
2065
  columnType: "PgText";
2066
- data: "google" | "github" | "kakao" | "naver";
2066
+ data: "google" | "github" | "kakao" | "naver" | "superself";
2067
2067
  driverParam: string;
2068
2068
  notNull: true;
2069
2069
  hasDefault: false;
2070
2070
  isPrimaryKey: false;
2071
2071
  isAutoincrement: false;
2072
2072
  hasRuntimeDefault: false;
2073
- enumValues: ["google", "github", "kakao", "naver"] & [string, ...string[]];
2073
+ enumValues: ["google", "github", "kakao", "naver", "superself"] & [string, ...string[]];
2074
2074
  baseColumn: never;
2075
2075
  identity: undefined;
2076
2076
  generated: undefined;
@@ -4412,7 +4412,7 @@ declare class SocialAccountsRepository extends BaseRepository {
4412
4412
  updatedAt: Date;
4413
4413
  id: number;
4414
4414
  userId: number;
4415
- provider: "google" | "github" | "kakao" | "naver";
4415
+ provider: "google" | "github" | "kakao" | "naver" | "superself";
4416
4416
  providerUserId: string;
4417
4417
  providerEmail: string | null;
4418
4418
  accessToken: string | null;
@@ -4428,7 +4428,7 @@ declare class SocialAccountsRepository extends BaseRepository {
4428
4428
  updatedAt: Date;
4429
4429
  id: number;
4430
4430
  userId: number;
4431
- provider: "google" | "github" | "kakao" | "naver";
4431
+ provider: "google" | "github" | "kakao" | "naver" | "superself";
4432
4432
  providerUserId: string;
4433
4433
  providerEmail: string | null;
4434
4434
  accessToken: string | null;
@@ -4444,7 +4444,7 @@ declare class SocialAccountsRepository extends BaseRepository {
4444
4444
  updatedAt: Date;
4445
4445
  id: number;
4446
4446
  userId: number;
4447
- provider: "google" | "github" | "kakao" | "naver";
4447
+ provider: "google" | "github" | "kakao" | "naver" | "superself";
4448
4448
  providerUserId: string;
4449
4449
  providerEmail: string | null;
4450
4450
  accessToken: string | null;
@@ -4460,7 +4460,7 @@ declare class SocialAccountsRepository extends BaseRepository {
4460
4460
  id: number;
4461
4461
  createdAt: Date;
4462
4462
  updatedAt: Date;
4463
- provider: "google" | "github" | "kakao" | "naver";
4463
+ provider: "google" | "github" | "kakao" | "naver" | "superself";
4464
4464
  providerUserId: string;
4465
4465
  providerEmail: string | null;
4466
4466
  accessToken: string | null;
@@ -4480,7 +4480,7 @@ declare class SocialAccountsRepository extends BaseRepository {
4480
4480
  updatedAt: Date;
4481
4481
  id: number;
4482
4482
  userId: number;
4483
- provider: "google" | "github" | "kakao" | "naver";
4483
+ provider: "google" | "github" | "kakao" | "naver" | "superself";
4484
4484
  providerUserId: string;
4485
4485
  providerEmail: string | null;
4486
4486
  accessToken: string | null;
@@ -4496,7 +4496,7 @@ declare class SocialAccountsRepository extends BaseRepository {
4496
4496
  id: number;
4497
4497
  createdAt: Date;
4498
4498
  updatedAt: Date;
4499
- provider: "google" | "github" | "kakao" | "naver";
4499
+ provider: "google" | "github" | "kakao" | "naver" | "superself";
4500
4500
  providerUserId: string;
4501
4501
  providerEmail: string | null;
4502
4502
  accessToken: string | null;
@@ -4512,7 +4512,7 @@ declare class SocialAccountsRepository extends BaseRepository {
4512
4512
  id: number;
4513
4513
  createdAt: Date;
4514
4514
  updatedAt: Date;
4515
- provider: "google" | "github" | "kakao" | "naver";
4515
+ provider: "google" | "github" | "kakao" | "naver" | "superself";
4516
4516
  providerUserId: string;
4517
4517
  providerEmail: string | null;
4518
4518
  accessToken: string | null;
@@ -5291,6 +5291,99 @@ declare function createOAuthState(params: CreateOAuthStateParams): Promise<strin
5291
5291
  */
5292
5292
  declare function verifyOAuthState(encryptedState: string): Promise<OAuthState>;
5293
5293
 
5294
+ /**
5295
+ * OAuth Provider 추상화
5296
+ *
5297
+ * Provider별로 하드코딩된 분기를 제거하기 위한 공통 인터페이스와 registry.
5298
+ * - 내장 provider(google)는 패키지 로드 시점에 자기 등록(dogfood)
5299
+ * - 외부 패키지(@superself/auth 등)는 registerOAuthProvider()로 런타임 등록
5300
+ *
5301
+ * @spfn/auth는 토큰 issuer가 아니라 소비(client) 측이므로,
5302
+ * 이 추상화는 "authorize URL 생성 → code 교환 → 사용자 정보 정규화"까지만 다룬다.
5303
+ */
5304
+
5305
+ /**
5306
+ * Provider 사용자 정보를 공통 형태로 정규화한 신원
5307
+ *
5308
+ * provider별 응답 형태(snake_case 등)를 service에 노출하지 않기 위한 경계.
5309
+ */
5310
+ interface NormalizedIdentity {
5311
+ providerUserId: string;
5312
+ email: string | null;
5313
+ emailVerified: boolean;
5314
+ name?: string;
5315
+ avatar?: string;
5316
+ }
5317
+ /**
5318
+ * 정규화된 OAuth 토큰 응답
5319
+ *
5320
+ * @property expiresIn - access token 만료까지 남은 초(seconds)
5321
+ */
5322
+ interface OAuthTokens {
5323
+ accessToken: string;
5324
+ refreshToken?: string;
5325
+ expiresIn: number;
5326
+ }
5327
+ /**
5328
+ * OAuth provider 구현 인터페이스
5329
+ *
5330
+ * google, superself 등 모든 provider가 이 형태를 만족해야 registry에 등록된다.
5331
+ */
5332
+ interface OAuthProvider {
5333
+ id: SocialProvider;
5334
+ /**
5335
+ * provider가 사용 가능한 상태인지(필수 env 등) 확인
5336
+ */
5337
+ isEnabled(): boolean;
5338
+ /**
5339
+ * provider 로그인 페이지로 보낼 authorization URL 생성
5340
+ *
5341
+ * @param state - CSRF 방지용 암호화 state
5342
+ * @param scopes - 요청할 scope (미지정 시 provider 기본값)
5343
+ */
5344
+ getAuthUrl(state: string, scopes?: string[]): string;
5345
+ /**
5346
+ * authorization code를 토큰으로 교환
5347
+ */
5348
+ exchangeCodeForTokens(code: string): Promise<OAuthTokens>;
5349
+ /**
5350
+ * access token으로 사용자 정보를 조회하고 공통 형태로 정규화
5351
+ */
5352
+ getUserInfo(accessToken: string): Promise<NormalizedIdentity>;
5353
+ /**
5354
+ * refresh token으로 access token 갱신 (provider가 지원하는 경우)
5355
+ *
5356
+ * 저장된 provider 토큰을 이후 API 호출에 재사용할 때 사용한다.
5357
+ * 미구현 provider는 갱신 불가로 간주한다.
5358
+ */
5359
+ refreshTokens?(refreshToken: string): Promise<OAuthTokens>;
5360
+ }
5361
+ /**
5362
+ * OAuth provider 등록 (public)
5363
+ *
5364
+ * 동일 id로 다시 등록하면 덮어쓴다(외부 패키지의 override 허용).
5365
+ */
5366
+ declare function registerOAuthProvider(provider: OAuthProvider): void;
5367
+ /**
5368
+ * 등록된 provider 조회. 미등록이면 undefined.
5369
+ */
5370
+ declare function getOAuthProvider(id: SocialProvider): OAuthProvider | undefined;
5371
+ /**
5372
+ * 등록된 모든 provider 목록
5373
+ */
5374
+ declare function getRegisteredProviders(): OAuthProvider[];
5375
+
5376
+ /**
5377
+ * Google OAuthProvider 구현
5378
+ *
5379
+ * 기존 google.ts의 함수를 OAuthProvider 인터페이스로 래핑한다.
5380
+ * google.ts 자체는 그대로 유지(테스트·google 전용 route가 직접 의존).
5381
+ *
5382
+ * 이 모듈을 import 하는 것만으로 google provider가 registry에 자기 등록된다.
5383
+ */
5384
+
5385
+ declare const googleProvider: OAuthProvider;
5386
+
5294
5387
  /**
5295
5388
  * One-Time Token Manager
5296
5389
  *
@@ -5483,8 +5576,10 @@ declare function createAuthLifecycle(options?: AuthLifecycleOptions): AuthLifecy
5483
5576
  */
5484
5577
  /**
5485
5578
  * Auth provider type
5579
+ *
5580
+ * 직접 인증(email/phone) + 등록 가능한 모든 소셜 provider(SOCIAL_PROVIDERS).
5486
5581
  */
5487
- declare const AuthProviderSchema: _sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"email">, _sinclair_typebox.TLiteral<"phone">, _sinclair_typebox.TLiteral<"google">]>;
5582
+ declare const AuthProviderSchema: _sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"email">, _sinclair_typebox.TLiteral<"phone">, ..._sinclair_typebox.TLiteral<"google" | "github" | "kakao" | "naver" | "superself">[]]>;
5488
5583
  /**
5489
5584
  * auth.login - 로그인 성공 이벤트
5490
5585
  *
@@ -5503,7 +5598,7 @@ declare const authLoginEvent: _spfn_core_event.EventDef<{
5503
5598
  email?: string | undefined;
5504
5599
  phone?: string | undefined;
5505
5600
  userId: string;
5506
- provider: "email" | "phone" | "google";
5601
+ provider: "email" | "phone" | "google" | "github" | "kakao" | "naver" | "superself";
5507
5602
  }>;
5508
5603
  /**
5509
5604
  * auth.register - 회원가입 성공 이벤트
@@ -5526,7 +5621,7 @@ declare const authRegisterEvent: _spfn_core_event.EventDef<{
5526
5621
  [x: string]: unknown;
5527
5622
  } | undefined;
5528
5623
  userId: string;
5529
- provider: "email" | "phone" | "google";
5624
+ provider: "email" | "phone" | "google" | "github" | "kakao" | "naver" | "superself";
5530
5625
  }>;
5531
5626
  /**
5532
5627
  * auth.invitation.created - 초대 생성 이벤트
@@ -5591,4 +5686,4 @@ type AuthRegisterPayload = typeof authRegisterEvent._payload;
5591
5686
  type InvitationCreatedPayload = typeof invitationCreatedEvent._payload;
5592
5687
  type InvitationAcceptedPayload = typeof invitationAcceptedEvent._payload;
5593
5688
 
5594
- export { type AuthConfig, AuthContext, type AuthLifecycleConfig, type AuthLifecycleOptions, type AuthLoginPayload, type AuthMetadataEntity, AuthMetadataRepository, AuthProviderSchema, type AuthRegisterPayload, COOKIE_NAMES, type CreateOAuthStateParams, type GoogleTokenResponse, type GoogleUserInfo, type Invitation, type InvitationAcceptedPayload, type InvitationCreatedPayload, InvitationStatus, InvitationsRepository, KeyAlgorithmType, type KeyPair, KeysRepository, type NewAuthMetadataEntity, type NewInvitation, type NewPermission, type NewPermissionEntity, type NewRole, type NewRoleEntity, type NewRolePermission, type NewUser, type NewUserPermission, type NewUserProfile, type NewUserPublicKey, type NewUserSocialAccount, type NewVerificationCode, type OAuthState, type Permission, type PermissionEntity, PermissionsRepository, type Role, type RoleEntity, type RoleGuardOptions, type RolePermission, RolePermissionsRepository, RolesRepository, type SessionPayload, SocialAccountsRepository, SocialProvider, type TokenPayload, type UpdateProfileParams, type User, type UserPermission, UserPermissionsRepository, type UserProfile, UserProfilesRepository, type UserPublicKey, type UserSocialAccount, UsersRepository, type VerificationCode, VerificationCodesRepository, VerificationPurpose, acceptInvitation, addPermissionToRole, authLogger, authLoginEvent, authMetadata, authMetadataRepository, authRegisterEvent, authSchema, cancelInvitation, checkUsernameAvailableService, configureAuth, createAuthLifecycle, createInvitation, createOAuthState, createRole, decodeToken, deleteInvitation, deleteRole, exchangeCodeForTokens, expireOldInvitations, generateClientToken, generateKeyPair, generateKeyPairES256, generateKeyPairRS256, generateToken, getAllRoles, getAuth, getAuthConfig, getAuthSessionService, getGoogleAuthUrl, getGoogleOAuthConfig, getGoogleUserInfo, getInvitationByToken, getInvitationWithDetails, getKeyId, getKeySize, getLocale, getOneTimeTokenManager, getOptionalAuth, getRole, getRoleByName, getRolePermissions, getSessionTtl, getUser, getUserByEmailService, getUserByIdService, getUserByPhoneService, getUserId, getUserPermissions, getUserProfileService, getUserRole, hasAllPermissions, hasAnyPermission, hasAnyRole, hasPermission, hasRole, hashPassword, initOneTimeTokenManager, initializeAuth, invitationAcceptedEvent, invitationCreatedEvent, invitationsRepository, isGoogleOAuthEnabled, keysRepository, listInvitations, oneTimeTokenAuth, parseDuration, permissions, permissionsRepository, refreshAccessToken, removePermissionFromRole, requireAnyPermission, requirePermissions, requireRole, resendInvitation, roleGuard, rolePermissions, rolePermissionsRepository, roles, rolesRepository, setRolePermissions, shouldRotateKey, socialAccountsRepository, updateLastLoginService, updateLocaleService, updateRole, updateUserProfileService, updateUserService, updateUsernameService, userInvitations, userPermissions, userPermissionsRepository, userProfiles, userProfilesRepository, userPublicKeys, userSocialAccounts, users, usersRepository, validateInvitation, validatePasswordStrength, verificationCodes, verificationCodesRepository, verifyClientToken, verifyKeyFingerprint, verifyOAuthState, verifyPassword, verifyToken };
5689
+ export { type AuthConfig, AuthContext, type AuthLifecycleConfig, type AuthLifecycleOptions, type AuthLoginPayload, type AuthMetadataEntity, AuthMetadataRepository, AuthProviderSchema, type AuthRegisterPayload, COOKIE_NAMES, type CreateOAuthStateParams, type GoogleTokenResponse, type GoogleUserInfo, type Invitation, type InvitationAcceptedPayload, type InvitationCreatedPayload, InvitationStatus, InvitationsRepository, KeyAlgorithmType, type KeyPair, KeysRepository, type NewAuthMetadataEntity, type NewInvitation, type NewPermission, type NewPermissionEntity, type NewRole, type NewRoleEntity, type NewRolePermission, type NewUser, type NewUserPermission, type NewUserProfile, type NewUserPublicKey, type NewUserSocialAccount, type NewVerificationCode, type NormalizedIdentity, type OAuthProvider, type OAuthState, type OAuthTokens, type Permission, type PermissionEntity, PermissionsRepository, type Role, type RoleEntity, type RoleGuardOptions, type RolePermission, RolePermissionsRepository, RolesRepository, type SessionPayload, SocialAccountsRepository, SocialProvider, type TokenPayload, type UpdateProfileParams, type User, type UserPermission, UserPermissionsRepository, type UserProfile, UserProfilesRepository, type UserPublicKey, type UserSocialAccount, UsersRepository, type VerificationCode, VerificationCodesRepository, VerificationPurpose, acceptInvitation, addPermissionToRole, authLogger, authLoginEvent, authMetadata, authMetadataRepository, authRegisterEvent, authSchema, cancelInvitation, checkUsernameAvailableService, configureAuth, createAuthLifecycle, createInvitation, createOAuthState, createRole, decodeToken, deleteInvitation, deleteRole, exchangeCodeForTokens, expireOldInvitations, generateClientToken, generateKeyPair, generateKeyPairES256, generateKeyPairRS256, generateToken, getAllRoles, getAuth, getAuthConfig, getAuthSessionService, getGoogleAuthUrl, getGoogleOAuthConfig, getGoogleUserInfo, getInvitationByToken, getInvitationWithDetails, getKeyId, getKeySize, getLocale, getOAuthProvider, getOneTimeTokenManager, getOptionalAuth, getRegisteredProviders, getRole, getRoleByName, getRolePermissions, getSessionTtl, getUser, getUserByEmailService, getUserByIdService, getUserByPhoneService, getUserId, getUserPermissions, getUserProfileService, getUserRole, googleProvider, hasAllPermissions, hasAnyPermission, hasAnyRole, hasPermission, hasRole, hashPassword, initOneTimeTokenManager, initializeAuth, invitationAcceptedEvent, invitationCreatedEvent, invitationsRepository, isGoogleOAuthEnabled, keysRepository, listInvitations, oneTimeTokenAuth, parseDuration, permissions, permissionsRepository, refreshAccessToken, registerOAuthProvider, removePermissionFromRole, requireAnyPermission, requirePermissions, requireRole, resendInvitation, roleGuard, rolePermissions, rolePermissionsRepository, roles, rolesRepository, setRolePermissions, shouldRotateKey, socialAccountsRepository, updateLastLoginService, updateLocaleService, updateRole, updateUserProfileService, updateUserService, updateUsernameService, userInvitations, userPermissions, userPermissionsRepository, userProfiles, userProfilesRepository, userPublicKeys, userSocialAccounts, users, usersRepository, validateInvitation, validatePasswordStrength, verificationCodes, verificationCodesRepository, verifyClientToken, verifyKeyFingerprint, verifyOAuthState, verifyPassword, verifyToken };
package/dist/server.js CHANGED
@@ -4501,7 +4501,7 @@ var init_types = __esm({
4501
4501
  KEY_ALGORITHM = ["ES256", "RS256"];
4502
4502
  INVITATION_STATUSES = ["pending", "accepted", "expired", "cancelled"];
4503
4503
  USER_STATUSES = ["active", "inactive", "suspended"];
4504
- SOCIAL_PROVIDERS = ["google", "github", "kakao", "naver"];
4504
+ SOCIAL_PROVIDERS = ["google", "github", "kakao", "naver", "superself"];
4505
4505
  }
4506
4506
  });
4507
4507
 
@@ -7211,11 +7211,12 @@ async function updateUsernameService(userId, username) {
7211
7211
 
7212
7212
  // src/server/events/index.ts
7213
7213
  init_esm();
7214
+ init_types();
7214
7215
  import { defineEvent } from "@spfn/core/event";
7215
7216
  var AuthProviderSchema = Type.Union([
7216
7217
  Type.Literal("email"),
7217
7218
  Type.Literal("phone"),
7218
- Type.Literal("google")
7219
+ ...SOCIAL_PROVIDERS.map((p) => Type.Literal(p))
7219
7220
  ]);
7220
7221
  var authLoginEvent = defineEvent(
7221
7222
  "auth.login",
@@ -8161,30 +8162,88 @@ async function verifyOAuthState(encryptedState) {
8161
8162
  return payload.state;
8162
8163
  }
8163
8164
 
8165
+ // src/server/lib/oauth/provider.ts
8166
+ var registry = /* @__PURE__ */ new Map();
8167
+ function registerOAuthProvider(provider) {
8168
+ registry.set(provider.id, provider);
8169
+ }
8170
+ function getOAuthProvider(id11) {
8171
+ return registry.get(id11);
8172
+ }
8173
+ function getRegisteredProviders() {
8174
+ return [...registry.values()];
8175
+ }
8176
+
8177
+ // src/server/lib/oauth/google-provider.ts
8178
+ var googleProvider = {
8179
+ id: "google",
8180
+ isEnabled: isGoogleOAuthEnabled,
8181
+ getAuthUrl: getGoogleAuthUrl,
8182
+ async exchangeCodeForTokens(code) {
8183
+ const tokens = await exchangeCodeForTokens(code);
8184
+ return {
8185
+ accessToken: tokens.access_token,
8186
+ refreshToken: tokens.refresh_token,
8187
+ expiresIn: tokens.expires_in
8188
+ };
8189
+ },
8190
+ async getUserInfo(accessToken) {
8191
+ const user = await getGoogleUserInfo(accessToken);
8192
+ return {
8193
+ providerUserId: user.id,
8194
+ email: user.email ?? null,
8195
+ emailVerified: user.verified_email,
8196
+ name: user.name,
8197
+ avatar: user.picture
8198
+ };
8199
+ },
8200
+ async refreshTokens(refreshToken) {
8201
+ const tokens = await refreshAccessToken(refreshToken);
8202
+ return {
8203
+ accessToken: tokens.access_token,
8204
+ refreshToken: tokens.refresh_token,
8205
+ expiresIn: tokens.expires_in
8206
+ };
8207
+ }
8208
+ };
8209
+ registerOAuthProvider(googleProvider);
8210
+
8164
8211
  // src/server/services/oauth.service.ts
8165
- async function oauthStartService(params) {
8166
- const { provider, returnUrl, publicKey, keyId, fingerprint, algorithm, metadata } = params;
8167
- if (provider === "google") {
8168
- if (!isGoogleOAuthEnabled()) {
8169
- throw new ValidationError3({
8170
- message: "Google OAuth is not configured. Set SPFN_AUTH_GOOGLE_CLIENT_ID and SPFN_AUTH_GOOGLE_CLIENT_SECRET."
8171
- });
8172
- }
8173
- const state = await createOAuthState({
8174
- provider: "google",
8175
- returnUrl,
8176
- publicKey,
8177
- keyId,
8178
- fingerprint,
8179
- algorithm,
8180
- metadata
8212
+ function requireEnabledProvider(provider) {
8213
+ const oauthProvider = getOAuthProvider(provider);
8214
+ if (!oauthProvider) {
8215
+ throw new ValidationError3({
8216
+ message: `Unsupported OAuth provider: ${provider}. No provider is registered for this id.`
8217
+ });
8218
+ }
8219
+ if (!oauthProvider.isEnabled()) {
8220
+ throw new ValidationError3({
8221
+ message: `OAuth provider '${provider}' is registered but not configured. Check its required environment variables.`
8181
8222
  });
8182
- const authUrl = getGoogleAuthUrl(state);
8183
- return { authUrl };
8184
8223
  }
8185
- throw new ValidationError3({
8186
- message: `Unsupported OAuth provider: ${provider}`
8224
+ return oauthProvider;
8225
+ }
8226
+ function tokenExpiryDate(expiresIn) {
8227
+ if (!Number.isFinite(expiresIn)) {
8228
+ throw new ValidationError3({
8229
+ message: `Invalid token expiry returned from OAuth provider: ${expiresIn}`
8230
+ });
8231
+ }
8232
+ return new Date(Date.now() + expiresIn * 1e3);
8233
+ }
8234
+ async function oauthStartService(params) {
8235
+ const { provider, returnUrl, publicKey, keyId, fingerprint, algorithm, metadata } = params;
8236
+ const oauthProvider = requireEnabledProvider(provider);
8237
+ const state = await createOAuthState({
8238
+ provider,
8239
+ returnUrl,
8240
+ publicKey,
8241
+ keyId,
8242
+ fingerprint,
8243
+ algorithm,
8244
+ metadata
8187
8245
  });
8246
+ return { authUrl: oauthProvider.getAuthUrl(state) };
8188
8247
  }
8189
8248
  async function oauthCallbackService(params) {
8190
8249
  const { provider, code, state } = params;
@@ -8194,31 +8253,24 @@ async function oauthCallbackService(params) {
8194
8253
  message: "OAuth state provider mismatch"
8195
8254
  });
8196
8255
  }
8197
- if (provider === "google") {
8198
- return handleGoogleCallback(code, stateData);
8199
- }
8200
- throw new ValidationError3({
8201
- message: `Unsupported OAuth provider: ${provider}`
8202
- });
8203
- }
8204
- async function handleGoogleCallback(code, stateData) {
8205
- const tokens = await exchangeCodeForTokens(code);
8206
- const googleUser = await getGoogleUserInfo(tokens.access_token);
8256
+ const oauthProvider = requireEnabledProvider(provider);
8257
+ const tokens = await oauthProvider.exchangeCodeForTokens(code);
8258
+ const identity = await oauthProvider.getUserInfo(tokens.accessToken);
8207
8259
  const existingSocialAccount = await socialAccountsRepository.findByProviderAndProviderId(
8208
- "google",
8209
- googleUser.id
8260
+ provider,
8261
+ identity.providerUserId
8210
8262
  );
8211
8263
  let userId;
8212
8264
  let isNewUser = false;
8213
8265
  if (existingSocialAccount) {
8214
8266
  userId = existingSocialAccount.userId;
8215
8267
  await socialAccountsRepository.updateTokens(existingSocialAccount.id, {
8216
- accessToken: tokens.access_token,
8217
- refreshToken: tokens.refresh_token ?? existingSocialAccount.refreshToken,
8218
- tokenExpiresAt: new Date(Date.now() + tokens.expires_in * 1e3)
8268
+ accessToken: tokens.accessToken,
8269
+ refreshToken: tokens.refreshToken ?? existingSocialAccount.refreshToken,
8270
+ tokenExpiresAt: tokenExpiryDate(tokens.expiresIn)
8219
8271
  });
8220
8272
  } else {
8221
- const result = await createOrLinkUser(googleUser, tokens);
8273
+ const result = await createOrLinkUser(provider, identity, tokens);
8222
8274
  userId = result.userId;
8223
8275
  isNewUser = result.isNewUser;
8224
8276
  }
@@ -8242,7 +8294,7 @@ async function handleGoogleCallback(code, stateData) {
8242
8294
  const user = await usersRepository.findById(userId);
8243
8295
  const eventPayload = {
8244
8296
  userId: String(userId),
8245
- provider: "google",
8297
+ provider,
8246
8298
  email: user?.email || void 0,
8247
8299
  phone: user?.phone || void 0,
8248
8300
  metadata: stateData.metadata
@@ -8259,14 +8311,14 @@ async function handleGoogleCallback(code, stateData) {
8259
8311
  isNewUser
8260
8312
  };
8261
8313
  }
8262
- async function createOrLinkUser(googleUser, tokens) {
8263
- const existingUser = googleUser.email ? await usersRepository.findByEmail(googleUser.email) : null;
8314
+ async function createOrLinkUser(provider, identity, tokens) {
8315
+ const existingUser = identity.email ? await usersRepository.findByEmail(identity.email) : null;
8264
8316
  let userId;
8265
8317
  let isNewUser = false;
8266
8318
  if (existingUser) {
8267
- if (!googleUser.verified_email) {
8319
+ if (!identity.emailVerified) {
8268
8320
  throw new ValidationError3({
8269
- message: "Cannot link to existing account with unverified email. Please verify your email with Google first."
8321
+ message: "Cannot link to existing account with unverified email. Please verify your email with the provider first."
8270
8322
  });
8271
8323
  }
8272
8324
  userId = existingUser.id;
@@ -8282,26 +8334,26 @@ async function createOrLinkUser(googleUser, tokens) {
8282
8334
  throw new Error("Default user role not found. Run initializeAuth() first.");
8283
8335
  }
8284
8336
  const newUser = await usersRepository.create({
8285
- email: googleUser.verified_email ? googleUser.email : null,
8337
+ email: identity.emailVerified ? identity.email : null,
8286
8338
  phone: null,
8287
8339
  passwordHash: null,
8288
8340
  // OAuth 사용자는 비밀번호 없음
8289
8341
  passwordChangeRequired: false,
8290
8342
  roleId: userRole.id,
8291
8343
  status: "active",
8292
- emailVerifiedAt: googleUser.verified_email ? /* @__PURE__ */ new Date() : null
8344
+ emailVerifiedAt: identity.emailVerified ? /* @__PURE__ */ new Date() : null
8293
8345
  });
8294
8346
  userId = newUser.id;
8295
8347
  isNewUser = true;
8296
8348
  }
8297
8349
  await socialAccountsRepository.create({
8298
8350
  userId,
8299
- provider: "google",
8300
- providerUserId: googleUser.id,
8301
- providerEmail: googleUser.email,
8302
- accessToken: tokens.access_token,
8303
- refreshToken: tokens.refresh_token ?? null,
8304
- tokenExpiresAt: new Date(Date.now() + tokens.expires_in * 1e3)
8351
+ provider,
8352
+ providerUserId: identity.providerUserId,
8353
+ providerEmail: identity.email,
8354
+ accessToken: tokens.accessToken,
8355
+ refreshToken: tokens.refreshToken ?? null,
8356
+ tokenExpiresAt: tokenExpiryDate(tokens.expiresIn)
8305
8357
  });
8306
8358
  return { userId, isNewUser };
8307
8359
  }
@@ -8320,23 +8372,10 @@ function buildOAuthErrorUrl(error) {
8320
8372
  return errorUrl.replace("{error}", encodeURIComponent(error));
8321
8373
  }
8322
8374
  function isOAuthProviderEnabled(provider) {
8323
- switch (provider) {
8324
- case "google":
8325
- return isGoogleOAuthEnabled();
8326
- case "github":
8327
- case "kakao":
8328
- case "naver":
8329
- return false;
8330
- default:
8331
- return false;
8332
- }
8375
+ return getOAuthProvider(provider)?.isEnabled() ?? false;
8333
8376
  }
8334
8377
  function getEnabledOAuthProviders() {
8335
- const providers = [];
8336
- if (isGoogleOAuthEnabled()) {
8337
- providers.push("google");
8338
- }
8339
- return providers;
8378
+ return getRegisteredProviders().filter((p) => p.isEnabled()).map((p) => p.id);
8340
8379
  }
8341
8380
  var TOKEN_EXPIRY_BUFFER_MS = 5 * 60 * 1e3;
8342
8381
  async function getGoogleAccessToken(userId) {
@@ -8359,7 +8398,7 @@ async function getGoogleAccessToken(userId) {
8359
8398
  await socialAccountsRepository.updateTokens(account.id, {
8360
8399
  accessToken: tokens.access_token,
8361
8400
  refreshToken: tokens.refresh_token ?? account.refreshToken,
8362
- tokenExpiresAt: new Date(Date.now() + tokens.expires_in * 1e3)
8401
+ tokenExpiresAt: tokenExpiryDate(tokens.expires_in)
8363
8402
  });
8364
8403
  return tokens.access_token;
8365
8404
  }
@@ -9788,8 +9827,10 @@ export {
9788
9827
  getKeyId,
9789
9828
  getKeySize,
9790
9829
  getLocale,
9830
+ getOAuthProvider,
9791
9831
  getOneTimeTokenManager,
9792
9832
  getOptionalAuth,
9833
+ getRegisteredProviders,
9793
9834
  getRole,
9794
9835
  getRoleByName,
9795
9836
  getRolePermissions,
@@ -9803,6 +9844,7 @@ export {
9803
9844
  getUserPermissions,
9804
9845
  getUserProfileService,
9805
9846
  getUserRole,
9847
+ googleProvider,
9806
9848
  hasAllPermissions,
9807
9849
  hasAnyPermission,
9808
9850
  hasAnyRole,
@@ -9829,6 +9871,7 @@ export {
9829
9871
  permissions,
9830
9872
  permissionsRepository,
9831
9873
  refreshAccessToken,
9874
+ registerOAuthProvider,
9832
9875
  registerPublicKeyService,
9833
9876
  registerService,
9834
9877
  removePermissionFromRole,