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

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.
@@ -364,6 +364,88 @@ declare function issueOneTimeTokenService(userId: string): Promise<IssueOneTimeT
364
364
  */
365
365
  declare function verifyOneTimeTokenService(token: string): Promise<string | null>;
366
366
 
367
+ /**
368
+ * OAuth Provider 추상화
369
+ *
370
+ * Provider별로 하드코딩된 분기를 제거하기 위한 공통 인터페이스와 registry.
371
+ * - 내장 provider(google)는 패키지 로드 시점에 자기 등록(dogfood)
372
+ * - 외부 패키지(@superself/auth 등)는 registerOAuthProvider()로 런타임 등록
373
+ *
374
+ * @spfn/auth는 토큰 issuer가 아니라 소비(client) 측이므로,
375
+ * 이 추상화는 "authorize URL 생성 → code 교환 → 사용자 정보 정규화"까지만 다룬다.
376
+ */
377
+
378
+ /**
379
+ * Provider 사용자 정보를 공통 형태로 정규화한 신원
380
+ *
381
+ * provider별 응답 형태(snake_case 등)를 service에 노출하지 않기 위한 경계.
382
+ */
383
+ interface NormalizedIdentity {
384
+ providerUserId: string;
385
+ email: string | null;
386
+ emailVerified: boolean;
387
+ name?: string;
388
+ avatar?: string;
389
+ }
390
+ /**
391
+ * 정규화된 OAuth 토큰 응답
392
+ *
393
+ * @property expiresIn - access token 만료까지 남은 초(seconds)
394
+ */
395
+ interface OAuthTokens {
396
+ accessToken: string;
397
+ refreshToken?: string;
398
+ expiresIn: number;
399
+ }
400
+ /**
401
+ * OAuth provider 구현 인터페이스
402
+ *
403
+ * google, superself 등 모든 provider가 이 형태를 만족해야 registry에 등록된다.
404
+ */
405
+ interface OAuthProvider {
406
+ id: SocialProvider;
407
+ /**
408
+ * provider가 사용 가능한 상태인지(필수 env 등) 확인
409
+ */
410
+ isEnabled(): boolean;
411
+ /**
412
+ * provider 로그인 페이지로 보낼 authorization URL 생성
413
+ *
414
+ * @param state - CSRF 방지용 암호화 state
415
+ * @param scopes - 요청할 scope (미지정 시 provider 기본값)
416
+ */
417
+ getAuthUrl(state: string, scopes?: string[]): string;
418
+ /**
419
+ * authorization code를 토큰으로 교환
420
+ */
421
+ exchangeCodeForTokens(code: string): Promise<OAuthTokens>;
422
+ /**
423
+ * access token으로 사용자 정보를 조회하고 공통 형태로 정규화
424
+ */
425
+ getUserInfo(accessToken: string): Promise<NormalizedIdentity>;
426
+ /**
427
+ * refresh token으로 access token 갱신 (provider가 지원하는 경우)
428
+ *
429
+ * 저장된 provider 토큰을 이후 API 호출에 재사용할 때 사용한다.
430
+ * 미구현 provider는 갱신 불가로 간주한다.
431
+ */
432
+ refreshTokens?(refreshToken: string): Promise<OAuthTokens>;
433
+ }
434
+ /**
435
+ * OAuth provider 등록 (public)
436
+ *
437
+ * 동일 id로 다시 등록하면 덮어쓴다(외부 패키지의 override 허용).
438
+ */
439
+ declare function registerOAuthProvider(provider: OAuthProvider): void;
440
+ /**
441
+ * 등록된 provider 조회. 미등록이면 undefined.
442
+ */
443
+ declare function getOAuthProvider(id: SocialProvider): OAuthProvider | undefined;
444
+ /**
445
+ * 등록된 모든 provider 목록
446
+ */
447
+ declare function getRegisteredProviders(): OAuthProvider[];
448
+
367
449
  /**
368
450
  * @spfn/auth - OAuth Service
369
451
  *
@@ -396,6 +478,13 @@ interface OAuthCallbackResult {
396
478
  keyId: string;
397
479
  isNewUser: boolean;
398
480
  }
481
+ /**
482
+ * registry에서 provider를 찾아 사용 가능한지 검증 후 반환
483
+ *
484
+ * 미등록과 비활성을 구분해 디버깅 신호를 남긴다.
485
+ * 라우트 레이어에서도 재사용한다(중복 조회/non-null 단언 제거).
486
+ */
487
+ declare function requireEnabledProvider(provider: SocialProvider): OAuthProvider;
399
488
  /**
400
489
  * OAuth 로그인 시작 - Provider 로그인 페이지로 리다이렉트할 URL 생성
401
490
  *
@@ -531,7 +620,7 @@ declare const mainAuthRouter: _spfn_core_route.Router<{
531
620
  id: number;
532
621
  name: string;
533
622
  displayName: string;
534
- category: "auth" | "custom" | "user" | "rbac" | "system" | undefined;
623
+ category: "custom" | "user" | "auth" | "rbac" | "system" | undefined;
535
624
  }[];
536
625
  userId: number;
537
626
  publicId: string;
@@ -588,6 +677,36 @@ declare const mainAuthRouter: _spfn_core_route.Router<{
588
677
  keyId: string;
589
678
  returnUrl: string;
590
679
  }>;
680
+ oauthProviderStart: _spfn_core_route.RouteDef<{
681
+ params: _sinclair_typebox.TObject<{
682
+ provider: _sinclair_typebox.TUnion<_sinclair_typebox.TLiteral<"google" | "github" | "kakao" | "naver" | "superself">[]>;
683
+ }>;
684
+ query: _sinclair_typebox.TObject<{
685
+ state: _sinclair_typebox.TString;
686
+ }>;
687
+ }, {}, Response>;
688
+ oauthProviderCallback: _spfn_core_route.RouteDef<{
689
+ params: _sinclair_typebox.TObject<{
690
+ provider: _sinclair_typebox.TUnion<_sinclair_typebox.TLiteral<"google" | "github" | "kakao" | "naver" | "superself">[]>;
691
+ }>;
692
+ query: _sinclair_typebox.TObject<{
693
+ code: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
694
+ state: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
695
+ error: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
696
+ error_description: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
697
+ }>;
698
+ }, {}, Response>;
699
+ getProviderOAuthUrl: _spfn_core_route.RouteDef<{
700
+ params: _sinclair_typebox.TObject<{
701
+ provider: _sinclair_typebox.TUnion<_sinclair_typebox.TLiteral<"google" | "github" | "kakao" | "naver" | "superself">[]>;
702
+ }>;
703
+ body: _sinclair_typebox.TObject<{
704
+ returnUrl: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
705
+ state: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
706
+ }>;
707
+ }, {}, {
708
+ authUrl: string;
709
+ }>;
591
710
  getInvitation: _spfn_core_route.RouteDef<{
592
711
  params: _sinclair_typebox.TObject<{
593
712
  token: _sinclair_typebox.TString;
@@ -896,4 +1015,4 @@ declare const authenticate: _spfn_core_route.NamedMiddleware<"auth">;
896
1015
  */
897
1016
  declare const optionalAuth: _spfn_core_route.NamedMiddleware<"optionalAuth">;
898
1017
 
899
- export { authenticate as $, type AuthSession as A, registerPublicKeyService as B, type CheckAccountExistsResult as C, rotateKeyService as D, revokeKeyService as E, type RegisterPublicKeyParams as F, type RotateKeyParams as G, type RevokeKeyParams as H, type IssueOneTimeTokenResult as I, issueOneTimeTokenService as J, verifyOneTimeTokenService as K, type LoginResult as L, oauthStartService as M, oauthCallbackService as N, type OAuthStartResult as O, type PermissionConfig as P, buildOAuthErrorUrl as Q, type RoleConfig as R, type SendVerificationCodeResult as S, isOAuthProviderEnabled as T, type UserProfile as U, type VerificationTargetType as V, getEnabledOAuthProviders as W, getGoogleAccessToken as X, type OAuthStartParams as Y, type OAuthCallbackParams as Z, type OAuthCallbackResult as _, type RegisterResult as a, optionalAuth as a0, EmailSchema as a1, PhoneSchema as a2, PasswordSchema as a3, TargetTypeSchema as a4, VerificationPurposeSchema as a5, type RotateKeyResult as b, type ProfileInfo as c, type VerificationPurpose as d, VERIFICATION_TARGET_TYPES as e, VERIFICATION_PURPOSES as f, PERMISSION_CATEGORIES as g, type PermissionCategory as h, type AuthInitOptions as i, type AuthContext as j, checkAccountExistsService as k, loginService as l, mainAuthRouter as m, logoutService as n, changePasswordService as o, type CheckAccountExistsParams as p, type RegisterParams as q, registerService as r, type LoginParams as s, type LogoutParams as t, type ChangePasswordParams as u, sendVerificationCodeService as v, verifyCodeService as w, type SendVerificationCodeParams as x, type VerifyCodeParams as y, type VerifyCodeResult as z };
1018
+ export { type OAuthCallbackParams as $, type AuthSession as A, type VerifyCodeResult as B, type CheckAccountExistsResult as C, registerPublicKeyService as D, rotateKeyService as E, revokeKeyService as F, type RegisterPublicKeyParams as G, type RotateKeyParams as H, type IssueOneTimeTokenResult as I, type RevokeKeyParams as J, issueOneTimeTokenService as K, type LoginResult as L, verifyOneTimeTokenService as M, oauthStartService as N, type OAuthStartResult as O, type PermissionConfig as P, oauthCallbackService as Q, type RoleConfig as R, type SendVerificationCodeResult as S, buildOAuthErrorUrl as T, type UserProfile as U, type VerificationTargetType as V, isOAuthProviderEnabled as W, requireEnabledProvider as X, getEnabledOAuthProviders as Y, getGoogleAccessToken as Z, type OAuthStartParams as _, type RegisterResult as a, type OAuthCallbackResult as a0, authenticate as a1, optionalAuth as a2, EmailSchema as a3, PhoneSchema as a4, PasswordSchema as a5, TargetTypeSchema as a6, VerificationPurposeSchema as a7, type NormalizedIdentity as a8, type OAuthTokens as a9, registerOAuthProvider as aa, getOAuthProvider as ab, getRegisteredProviders as ac, type RotateKeyResult as b, type ProfileInfo as c, type VerificationPurpose as d, VERIFICATION_TARGET_TYPES as e, VERIFICATION_PURPOSES as f, PERMISSION_CATEGORIES as g, type PermissionCategory as h, type AuthInitOptions as i, type OAuthProvider as j, type AuthContext as k, checkAccountExistsService as l, mainAuthRouter as m, loginService as n, logoutService as o, changePasswordService as p, type CheckAccountExistsParams as q, registerService as r, type RegisterParams as s, type LoginParams as t, type LogoutParams as u, type ChangePasswordParams as v, sendVerificationCodeService as w, verifyCodeService as x, type SendVerificationCodeParams as y, type VerifyCodeParams as z };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
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-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';
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-mfVRzeIK.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-mfVRzeIK.js';
4
4
  import * as _spfn_core_route from '@spfn/core/route';
5
5
  import { HttpMethod } from '@spfn/core/route';
6
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';
@@ -170,7 +170,7 @@ declare const authApi: _spfn_core_nextjs.Client<_spfn_core_route.Router<{
170
170
  id: number;
171
171
  name: string;
172
172
  displayName: string;
173
- category: "auth" | "custom" | "user" | "rbac" | "system" | undefined;
173
+ category: "custom" | "user" | "auth" | "rbac" | "system" | undefined;
174
174
  }[];
175
175
  userId: number;
176
176
  publicId: string;
@@ -227,6 +227,36 @@ declare const authApi: _spfn_core_nextjs.Client<_spfn_core_route.Router<{
227
227
  keyId: string;
228
228
  returnUrl: string;
229
229
  }>;
230
+ oauthProviderStart: _spfn_core_route.RouteDef<{
231
+ params: _sinclair_typebox.TObject<{
232
+ provider: _sinclair_typebox.TUnion<_sinclair_typebox.TLiteral<"google" | "github" | "kakao" | "naver" | "superself">[]>;
233
+ }>;
234
+ query: _sinclair_typebox.TObject<{
235
+ state: _sinclair_typebox.TString;
236
+ }>;
237
+ }, {}, Response>;
238
+ oauthProviderCallback: _spfn_core_route.RouteDef<{
239
+ params: _sinclair_typebox.TObject<{
240
+ provider: _sinclair_typebox.TUnion<_sinclair_typebox.TLiteral<"google" | "github" | "kakao" | "naver" | "superself">[]>;
241
+ }>;
242
+ query: _sinclair_typebox.TObject<{
243
+ code: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
244
+ state: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
245
+ error: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
246
+ error_description: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
247
+ }>;
248
+ }, {}, Response>;
249
+ getProviderOAuthUrl: _spfn_core_route.RouteDef<{
250
+ params: _sinclair_typebox.TObject<{
251
+ provider: _sinclair_typebox.TUnion<_sinclair_typebox.TLiteral<"google" | "github" | "kakao" | "naver" | "superself">[]>;
252
+ }>;
253
+ body: _sinclair_typebox.TObject<{
254
+ returnUrl: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
255
+ state: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
256
+ }>;
257
+ }, {}, {
258
+ authUrl: string;
259
+ }>;
230
260
  getInvitation: _spfn_core_route.RouteDef<{
231
261
  params: _sinclair_typebox.TObject<{
232
262
  token: _sinclair_typebox.TString;
package/dist/index.js CHANGED
@@ -191,6 +191,9 @@ var routeMap = {
191
191
  oauthProviders: { method: "GET", path: "/_auth/oauth/providers" },
192
192
  getGoogleOAuthUrl: { method: "POST", path: "/_auth/oauth/google/url" },
193
193
  oauthFinalize: { method: "POST", path: "/_auth/oauth/finalize" },
194
+ oauthProviderStart: { method: "GET", path: "/_auth/oauth/:provider" },
195
+ oauthProviderCallback: { method: "GET", path: "/_auth/oauth/:provider/callback" },
196
+ getProviderOAuthUrl: { method: "POST", path: "/_auth/oauth/:provider/url" },
194
197
  listRoles: { method: "GET", path: "/_auth/admin/roles" },
195
198
  createAdminRole: { method: "POST", path: "/_auth/admin/roles" },
196
199
  updateAdminRole: { method: "PATCH", path: "/_auth/admin/roles/:id" },