@spfn/auth 0.2.0-beta.60 → 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.
package/README.md CHANGED
@@ -1540,10 +1540,12 @@ OAuth 세션 완료. 인터셉터가 pending session에서 full session을 생
1540
1540
  **Response:**
1541
1541
  ```typescript
1542
1542
  {
1543
- providers: ('google' | 'github' | 'kakao' | 'naver')[];
1543
+ providers: ('google' | 'github' | 'kakao' | 'naver' | 'superself')[];
1544
1544
  }
1545
1545
  ```
1546
1546
 
1547
+ > 등록(`registerOAuthProvider`)되고 `isEnabled()`가 true인 provider만 반환됩니다.
1548
+
1547
1549
  ---
1548
1550
 
1549
1551
  ### Google API Access
@@ -1585,6 +1587,62 @@ const data = await response.json();
1585
1587
 
1586
1588
  ---
1587
1589
 
1590
+ ### Custom OAuth Providers (Pluggable)
1591
+
1592
+ OAuth provider 분기는 하드코딩이 아니라 **registry 기반**입니다. 내장 `google` provider는 패키지 로드 시 자기 등록되며, 외부 패키지(예: `@superself/auth`)는 `registerOAuthProvider()`로 런타임에 provider를 끼울 수 있습니다.
1593
+
1594
+ #### `OAuthProvider` 인터페이스
1595
+
1596
+ ```typescript
1597
+ import type { OAuthProvider, NormalizedIdentity, OAuthTokens } from '@spfn/auth/server';
1598
+
1599
+ interface NormalizedIdentity {
1600
+ providerUserId: string;
1601
+ email: string | null;
1602
+ emailVerified: boolean;
1603
+ name?: string;
1604
+ avatar?: string;
1605
+ }
1606
+
1607
+ interface OAuthTokens {
1608
+ accessToken: string;
1609
+ refreshToken?: string;
1610
+ expiresIn: number; // seconds
1611
+ }
1612
+
1613
+ interface OAuthProvider {
1614
+ id: SocialProvider; // SOCIAL_PROVIDERS 중 하나
1615
+ isEnabled(): boolean; // 필수 설정 충족 여부
1616
+ getAuthUrl(state: string, scopes?: string[]): string; // authorize URL 생성
1617
+ exchangeCodeForTokens(code: string): Promise<OAuthTokens>; // code → token
1618
+ getUserInfo(accessToken: string): Promise<NormalizedIdentity>; // 사용자 정보 정규화
1619
+ refreshTokens?(refreshToken: string): Promise<OAuthTokens>; // (선택) 토큰 갱신
1620
+ }
1621
+ ```
1622
+
1623
+ #### 등록 API
1624
+
1625
+ ```typescript
1626
+ import { registerOAuthProvider, getOAuthProvider, getRegisteredProviders } from '@spfn/auth/server';
1627
+
1628
+ registerOAuthProvider(myProvider); // 동일 id 재등록 시 override
1629
+ getOAuthProvider('superself'); // OAuthProvider | undefined
1630
+ getRegisteredProviders(); // OAuthProvider[]
1631
+ ```
1632
+
1633
+ provider를 등록하면 범용 시작 엔드포인트 `POST /_auth/oauth/start`(및 `oauthStartService`/`oauthCallbackService`)가 자동으로 해당 provider를 처리합니다.
1634
+
1635
+ #### 통합 계약 ⚠️
1636
+
1637
+ - **콜백 route는 소비 측 책임**입니다. 이 패키지는 `GET /_auth/oauth/google/callback`(google 고정)만 제공합니다. 커스텀 provider는 자신의 콜백 route에서 `oauthCallbackService({ provider, code, state })`를 호출해야 흐름이 완결됩니다.
1638
+ - **콜백 route는 `Transactional()`로 감싸세요.** `oauthCallbackService`는 사용자 생성/연결과 소셜 계정 저장을 순차로 수행하므로, 중간 실패 시 orphan user가 남지 않으려면 트랜잭션이 필요합니다. (내장 google 콜백 route도 `.use([Transactional()])`를 사용합니다.)
1639
+ - `SOCIAL_PROVIDERS` enum에 provider id가 포함되어 있어야 합니다. (현재: `google`, `github`, `kakao`, `naver`, `superself`)
1640
+ - 등록은 모듈 로드 시점의 side-effect입니다. 번들러에서 `package.json`에 `"sideEffects": false`를 추가하면 내장 google 등록이 tree-shake될 수 있으니 주의하세요.
1641
+
1642
+ > **이벤트 영향**: `auth.login` / `auth.register` 이벤트의 `provider` 필드에 이제 모든 `SOCIAL_PROVIDERS` 값이 들어올 수 있습니다. 구독자의 `switch(provider)`에 새 값 처리를 추가하세요.
1643
+
1644
+ ---
1645
+
1588
1646
  ### Security
1589
1647
 
1590
1648
  - **State 암호화**: JWE (A256GCM)로 state 파라미터 암호화. CSRF 방지용 nonce 포함.
@@ -1,5 +1,5 @@
1
1
  import * as _spfn_core_route from '@spfn/core/route';
2
- import { K as KeyAlgorithmType, d as SocialProvider } from './types-B1CzVZkU.js';
2
+ import { K as KeyAlgorithmType, d as SocialProvider } from './types-B4auHIax.js';
3
3
  import * as _sinclair_typebox from '@sinclair/typebox';
4
4
  import { Static } from '@sinclair/typebox';
5
5
  import { User } from '@spfn/auth/server';
@@ -414,11 +414,11 @@ declare function oauthCallbackService(params: OAuthCallbackParams): Promise<OAut
414
414
  */
415
415
  declare function buildOAuthErrorUrl(error: string): string;
416
416
  /**
417
- * OAuth provider가 활성화되어 있는지 확인
417
+ * OAuth provider가 등록되어 있고 활성화되어 있는지 확인
418
418
  */
419
419
  declare function isOAuthProviderEnabled(provider: SocialProvider): boolean;
420
420
  /**
421
- * 활성화된 모든 OAuth provider 목록
421
+ * 활성화된 모든 OAuth provider 목록 (registry 기반)
422
422
  */
423
423
  declare function getEnabledOAuthProviders(): SocialProvider[];
424
424
  /**
@@ -556,7 +556,7 @@ declare const mainAuthRouter: _spfn_core_route.Router<{
556
556
  }, {}, Response>;
557
557
  oauthStart: _spfn_core_route.RouteDef<{
558
558
  body: _sinclair_typebox.TObject<{
559
- provider: _sinclair_typebox.TUnion<_sinclair_typebox.TLiteral<"google" | "github" | "kakao" | "naver">[]>;
559
+ provider: _sinclair_typebox.TUnion<_sinclair_typebox.TLiteral<"google" | "github" | "kakao" | "naver" | "superself">[]>;
560
560
  returnUrl: _sinclair_typebox.TString;
561
561
  publicKey: _sinclair_typebox.TString;
562
562
  keyId: _sinclair_typebox.TString;
@@ -566,7 +566,7 @@ declare const mainAuthRouter: _spfn_core_route.Router<{
566
566
  }>;
567
567
  }, {}, OAuthStartResult>;
568
568
  oauthProviders: _spfn_core_route.RouteDef<{}, {}, {
569
- providers: ("google" | "github" | "kakao" | "naver")[];
569
+ providers: ("google" | "github" | "kakao" | "naver" | "superself")[];
570
570
  }>;
571
571
  getGoogleOAuthUrl: _spfn_core_route.RouteDef<{
572
572
  body: _sinclair_typebox.TObject<{
package/dist/index.d.ts CHANGED
@@ -1,9 +1,9 @@
1
1
  import * as _spfn_core_nextjs from '@spfn/core/nextjs';
2
- import { R as RoleConfig, P as PermissionConfig, C as CheckAccountExistsResult, S as SendVerificationCodeResult, a as RegisterResult, L as LoginResult, b as RotateKeyResult, I as IssueOneTimeTokenResult, O as OAuthStartResult, U as UserProfile, c as ProfileInfo, m as mainAuthRouter } from './authenticate-B_HkYBzq.js';
3
- export { i as AuthInitOptions, A as AuthSession, g as PERMISSION_CATEGORIES, h as PermissionCategory, f as VERIFICATION_PURPOSES, e as VERIFICATION_TARGET_TYPES, d as VerificationPurpose, V as VerificationTargetType } from './authenticate-B_HkYBzq.js';
2
+ import { R as RoleConfig, P as PermissionConfig, C as CheckAccountExistsResult, S as SendVerificationCodeResult, a as RegisterResult, L as LoginResult, b as RotateKeyResult, I as IssueOneTimeTokenResult, O as OAuthStartResult, U as UserProfile, c as ProfileInfo, m as mainAuthRouter } from './authenticate-DcOkuB7d.js';
3
+ export { i as AuthInitOptions, A as AuthSession, g as PERMISSION_CATEGORIES, h as PermissionCategory, f as VERIFICATION_PURPOSES, e as VERIFICATION_TARGET_TYPES, d as VerificationPurpose, V as VerificationTargetType } from './authenticate-DcOkuB7d.js';
4
4
  import * as _spfn_core_route from '@spfn/core/route';
5
5
  import { HttpMethod } from '@spfn/core/route';
6
- export { I as INVITATION_STATUSES, b as InvitationStatus, a as KEY_ALGORITHM, K as KeyAlgorithmType, S as SOCIAL_PROVIDERS, d as SocialProvider, U as USER_STATUSES, c as UserStatus } from './types-B1CzVZkU.js';
6
+ export { I as INVITATION_STATUSES, b as InvitationStatus, a as KEY_ALGORITHM, K as KeyAlgorithmType, S as SOCIAL_PROVIDERS, d as SocialProvider, U as USER_STATUSES, c as UserStatus } from './types-B4auHIax.js';
7
7
  import * as _sinclair_typebox from '@sinclair/typebox';
8
8
  import '@spfn/auth/server';
9
9
 
@@ -195,7 +195,7 @@ declare const authApi: _spfn_core_nextjs.Client<_spfn_core_route.Router<{
195
195
  }, {}, Response>;
196
196
  oauthStart: _spfn_core_route.RouteDef<{
197
197
  body: _sinclair_typebox.TObject<{
198
- provider: _sinclair_typebox.TUnion<_sinclair_typebox.TLiteral<"google" | "github" | "kakao" | "naver">[]>;
198
+ provider: _sinclair_typebox.TUnion<_sinclair_typebox.TLiteral<"google" | "github" | "kakao" | "naver" | "superself">[]>;
199
199
  returnUrl: _sinclair_typebox.TString;
200
200
  publicKey: _sinclair_typebox.TString;
201
201
  keyId: _sinclair_typebox.TString;
@@ -205,7 +205,7 @@ declare const authApi: _spfn_core_nextjs.Client<_spfn_core_route.Router<{
205
205
  }>;
206
206
  }, {}, OAuthStartResult>;
207
207
  oauthProviders: _spfn_core_route.RouteDef<{}, {}, {
208
- providers: ("google" | "github" | "kakao" | "naver")[];
208
+ providers: ("google" | "github" | "kakao" | "naver" | "superself")[];
209
209
  }>;
210
210
  getGoogleOAuthUrl: _spfn_core_route.RouteDef<{
211
211
  body: _sinclair_typebox.TObject<{
package/dist/index.js CHANGED
@@ -333,7 +333,7 @@ var BUILTIN_ROLE_PERMISSIONS = {
333
333
  var KEY_ALGORITHM = ["ES256", "RS256"];
334
334
  var INVITATION_STATUSES = ["pending", "accepted", "expired", "cancelled"];
335
335
  var USER_STATUSES = ["active", "inactive", "suspended"];
336
- var SOCIAL_PROVIDERS = ["google", "github", "kakao", "naver"];
336
+ var SOCIAL_PROVIDERS = ["google", "github", "kakao", "naver", "superself"];
337
337
 
338
338
  // ../../node_modules/.pnpm/@sinclair+typebox@0.34.41/node_modules/@sinclair/typebox/build/esm/type/guard/value.mjs
339
339
  var value_exports = {};