@spfn/auth 0.2.0-beta.2 → 0.2.0-beta.21

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/server.d.ts CHANGED
@@ -1,13 +1,14 @@
1
- import { k as AuthInitOptions, l as KeyAlgorithmType, n as InvitationStatus, f as VerificationPurpose, j as PermissionCategory, q as AuthContext } from './dto-CLYtuAom.js';
2
- export { B as ChangePasswordParams, w as CheckAccountExistsParams, C as CheckAccountExistsResult, X as EmailSchema, I as INVITATION_STATUSES, K as KEY_ALGORITHM, y as LoginParams, L as LoginResult, z as LogoutParams, Z as PasswordSchema, Y as PhoneSchema, x as RegisterParams, O as RegisterPublicKeyParams, a as RegisterResult, T as RevokeKeyParams, Q as RotateKeyParams, b as RotateKeyResult, e as SOCIAL_PROVIDERS, F as SendVerificationCodeParams, S as SendVerificationCodeResult, p as SocialProvider, _ as TargetTypeSchema, d as USER_STATUSES, o as UserStatus, h as VERIFICATION_PURPOSES, g as VERIFICATION_TARGET_TYPES, $ as VerificationPurposeSchema, V as VerificationTargetType, G as VerifyCodeParams, H as VerifyCodeResult, m as authRouter, W as authenticate, v as changePasswordService, r as checkAccountExistsService, t as loginService, u as logoutService, J as registerPublicKeyService, s as registerService, N as revokeKeyService, M as rotateKeyService, D as sendVerificationCodeService, E as verifyCodeService } from './dto-CLYtuAom.js';
1
+ import { k as AuthInitOptions, l as KeyAlgorithmType, n as InvitationStatus, f as VerificationPurpose, j as PermissionCategory, p as SocialProvider, q as AuthContext } from './authenticate-BmzJ6hTF.js';
2
+ export { B as ChangePasswordParams, w as CheckAccountExistsParams, C as CheckAccountExistsResult, a5 as EmailSchema, I as INVITATION_STATUSES, K as KEY_ALGORITHM, y as LoginParams, L as LoginResult, z as LogoutParams, a2 as OAuthCallbackParams, a3 as OAuthCallbackResult, a1 as OAuthStartParams, O as OAuthStartResult, a7 as PasswordSchema, a6 as PhoneSchema, x as RegisterParams, Q as RegisterPublicKeyParams, a as RegisterResult, W as RevokeKeyParams, T as RotateKeyParams, b as RotateKeyResult, e as SOCIAL_PROVIDERS, F as SendVerificationCodeParams, S as SendVerificationCodeResult, a8 as TargetTypeSchema, d as USER_STATUSES, o as UserStatus, h as VERIFICATION_PURPOSES, g as VERIFICATION_TARGET_TYPES, a9 as VerificationPurposeSchema, V as VerificationTargetType, G as VerifyCodeParams, H as VerifyCodeResult, m as authRouter, a4 as authenticate, Z as buildOAuthErrorUrl, v as changePasswordService, r as checkAccountExistsService, $ as getEnabledOAuthProviders, a0 as getGoogleAccessToken, _ as isOAuthProviderEnabled, t as loginService, u as logoutService, Y as oauthCallbackService, X as oauthStartService, J as registerPublicKeyService, s as registerService, N as revokeKeyService, M as rotateKeyService, D as sendVerificationCodeService, E as verifyCodeService } from './authenticate-BmzJ6hTF.js';
3
3
  import * as drizzle_orm_pg_core from 'drizzle-orm/pg-core';
4
- import { UserProfile as UserProfile$1 } from '@spfn/auth';
4
+ import { UserProfile as UserProfile$1, ProfileInfo } from '@spfn/auth';
5
5
  import { BaseRepository } from '@spfn/core/db';
6
6
  import { Context } from 'hono';
7
7
  import * as _spfn_core_route from '@spfn/core/route';
8
8
  import { Algorithm } from 'jsonwebtoken';
9
9
  import * as _spfn_core_logger from '@spfn/core/logger';
10
- import '@sinclair/typebox';
10
+ import * as _spfn_core_event from '@spfn/core/event';
11
+ import * as _sinclair_typebox from '@sinclair/typebox';
11
12
  import '@spfn/auth/server';
12
13
 
13
14
  /**
@@ -406,6 +407,19 @@ declare function hasAnyPermission(userId: string | number | bigint, permissionNa
406
407
  * ```
407
408
  */
408
409
  declare function hasAllPermissions(userId: string | number | bigint, permissionNames: string[]): Promise<boolean>;
410
+ /**
411
+ * Get user's role name
412
+ *
413
+ * @param userId - User ID
414
+ * @returns Role name or null if user has no role
415
+ *
416
+ * @example
417
+ * ```typescript
418
+ * const role = await getUserRole('123');
419
+ * // 'admin' or null
420
+ * ```
421
+ */
422
+ declare function getUserRole(userId: string | number | bigint): Promise<string | null>;
409
423
  /**
410
424
  * Check if user has a specific role
411
425
  *
@@ -1253,10 +1267,30 @@ declare function getAuthSessionService(userId: string | number | bigint): Promis
1253
1267
  /**
1254
1268
  * @spfn/auth - User Profile Service
1255
1269
  *
1256
- * Service for retrieving user profile information
1270
+ * Service for retrieving and updating user profile information
1257
1271
  * Returns full user info with profile data
1258
1272
  */
1259
1273
 
1274
+ /**
1275
+ * Profile update parameters
1276
+ * All fields are optional, empty string will be converted to null
1277
+ */
1278
+ interface UpdateProfileParams {
1279
+ displayName?: string;
1280
+ firstName?: string;
1281
+ lastName?: string;
1282
+ avatarUrl?: string;
1283
+ bio?: string;
1284
+ locale?: string;
1285
+ timezone?: string;
1286
+ dateOfBirth?: string;
1287
+ gender?: string;
1288
+ website?: string;
1289
+ location?: string;
1290
+ company?: string;
1291
+ jobTitle?: string;
1292
+ metadata?: Record<string, any>;
1293
+ }
1260
1294
  /**
1261
1295
  * Get user profile information
1262
1296
  *
@@ -1272,369 +1306,26 @@ declare function getAuthSessionService(userId: string | number | bigint): Promis
1272
1306
  * ```
1273
1307
  */
1274
1308
  declare function getUserProfileService(userId: string | number | bigint): Promise<UserProfile$1>;
1275
-
1276
- /**
1277
- * @spfn/auth - Email Template Types
1278
- *
1279
- * Type definitions for customizable email templates
1280
- */
1281
- /**
1282
- * Common template result
1283
- */
1284
- interface EmailTemplateResult {
1285
- subject: string;
1286
- text: string;
1287
- html: string;
1288
- }
1289
- /**
1290
- * Verification code template parameters
1291
- */
1292
- interface VerificationCodeParams {
1293
- code: string;
1294
- purpose: 'registration' | 'login' | 'password_reset' | string;
1295
- expiresInMinutes?: number;
1296
- appName?: string;
1297
- }
1298
1309
  /**
1299
- * Email template provider interface
1310
+ * Update user profile (upsert)
1300
1311
  *
1301
- * Implement this interface to create custom email templates
1312
+ * Creates profile if not exists, updates if exists
1313
+ * Empty strings are converted to null
1302
1314
  *
1303
- * @example
1304
- * ```typescript
1305
- * import { registerEmailTemplates } from '@spfn/auth/server';
1306
- *
1307
- * registerEmailTemplates({
1308
- * verificationCode: (params) => ({
1309
- * subject: 'Your Code',
1310
- * text: `Code: ${params.code}`,
1311
- * html: `<h1>Code: ${params.code}</h1>`,
1312
- * }),
1313
- * });
1314
- * ```
1315
- */
1316
- interface EmailTemplateProvider {
1317
- /**
1318
- * Verification code email template
1319
- */
1320
- verificationCode?(params: VerificationCodeParams): EmailTemplateResult;
1321
- /**
1322
- * Welcome email template (after registration)
1323
- */
1324
- welcome?(params: {
1325
- email: string;
1326
- appName?: string;
1327
- }): EmailTemplateResult;
1328
- /**
1329
- * Password reset email template
1330
- */
1331
- passwordReset?(params: {
1332
- resetLink: string;
1333
- expiresInMinutes?: number;
1334
- appName?: string;
1335
- }): EmailTemplateResult;
1336
- /**
1337
- * Invitation email template
1338
- */
1339
- invitation?(params: {
1340
- inviteLink: string;
1341
- inviterName?: string;
1342
- roleName?: string;
1343
- appName?: string;
1344
- }): EmailTemplateResult;
1345
- }
1346
-
1347
- /**
1348
- * @spfn/auth - Email Template Registry
1349
- *
1350
- * Manages custom email template registration and fallback to defaults
1351
- */
1352
-
1353
- /**
1354
- * Register custom email templates
1355
- *
1356
- * Templates not provided will fall back to defaults
1357
- *
1358
- * @param templates - Custom template implementations
1315
+ * @param userId - User ID
1316
+ * @param params - Profile fields to update
1317
+ * @returns Updated profile info
1359
1318
  *
1360
1319
  * @example
1361
1320
  * ```typescript
1362
- * import { registerEmailTemplates } from '@spfn/auth/server';
1363
- *
1364
- * // Override verification code template with custom design
1365
- * registerEmailTemplates({
1366
- * verificationCode: ({ code, purpose, expiresInMinutes }) => ({
1367
- * subject: `[MyApp] Your verification code`,
1368
- * text: `Your code is: ${code}`,
1369
- * html: `
1370
- * <div style="font-family: Arial;">
1371
- * <h1>Welcome to MyApp!</h1>
1372
- * <p>Your code: <strong>${code}</strong></p>
1373
- * </div>
1374
- * `,
1375
- * }),
1321
+ * const profile = await updateUserProfileService(123, {
1322
+ * displayName: 'John Doe',
1323
+ * bio: 'Software Engineer',
1324
+ * location: '', // will be saved as null
1376
1325
  * });
1377
1326
  * ```
1378
1327
  */
1379
- declare function registerEmailTemplates(templates: Partial<EmailTemplateProvider>): void;
1380
- /**
1381
- * Get verification code template
1382
- *
1383
- * Uses custom template if registered, otherwise falls back to default
1384
- */
1385
- declare function getVerificationCodeTemplate(params: VerificationCodeParams): EmailTemplateResult;
1386
- /**
1387
- * Get welcome template
1388
- */
1389
- declare function getWelcomeTemplate(params: {
1390
- email: string;
1391
- appName?: string;
1392
- }): EmailTemplateResult;
1393
- /**
1394
- * Get password reset template
1395
- */
1396
- declare function getPasswordResetTemplate(params: {
1397
- resetLink: string;
1398
- expiresInMinutes?: number;
1399
- appName?: string;
1400
- }): EmailTemplateResult;
1401
- /**
1402
- * Get invitation template
1403
- */
1404
- declare function getInvitationTemplate(params: {
1405
- inviteLink: string;
1406
- inviterName?: string;
1407
- roleName?: string;
1408
- appName?: string;
1409
- }): EmailTemplateResult;
1410
-
1411
- /**
1412
- * @spfn/auth - Email Service Types
1413
- *
1414
- * Type definitions for email sending service
1415
- */
1416
- /**
1417
- * Parameters for sending email
1418
- */
1419
- interface SendEmailParams {
1420
- /**
1421
- * Recipient email address
1422
- */
1423
- to: string;
1424
- /**
1425
- * Email subject
1426
- */
1427
- subject: string;
1428
- /**
1429
- * Plain text content
1430
- */
1431
- text?: string;
1432
- /**
1433
- * HTML content
1434
- */
1435
- html?: string;
1436
- /**
1437
- * Purpose of the email (for logging)
1438
- */
1439
- purpose?: string;
1440
- }
1441
- /**
1442
- * Result of sending email
1443
- */
1444
- interface SendEmailResult {
1445
- /**
1446
- * Whether email was sent successfully
1447
- */
1448
- success: boolean;
1449
- /**
1450
- * Message ID from email provider (if successful)
1451
- */
1452
- messageId?: string;
1453
- /**
1454
- * Error message (if failed)
1455
- */
1456
- error?: string;
1457
- }
1458
- /**
1459
- * Email Provider Interface
1460
- *
1461
- * Implement this interface to create custom email providers
1462
- *
1463
- * @example
1464
- * ```typescript
1465
- * import { EmailProvider, registerEmailProvider } from '@spfn/auth/server/services/email';
1466
- *
1467
- * const sendgridProvider: EmailProvider = {
1468
- * name: 'sendgrid',
1469
- * sendEmail: async (params) => {
1470
- * // Your SendGrid implementation
1471
- * return { success: true, messageId: '...' };
1472
- * }
1473
- * };
1474
- *
1475
- * registerEmailProvider(sendgridProvider);
1476
- * ```
1477
- */
1478
- interface EmailProvider {
1479
- /**
1480
- * Provider name (e.g., 'aws-ses', 'sendgrid', 'custom')
1481
- */
1482
- name: string;
1483
- /**
1484
- * Send email via this provider
1485
- *
1486
- * @param params - Email parameters
1487
- * @returns Send result
1488
- */
1489
- sendEmail(params: SendEmailParams): Promise<SendEmailResult>;
1490
- }
1491
-
1492
- /**
1493
- * @spfn/auth - Email Provider Management
1494
- *
1495
- * Manages email provider registration and fallback behavior
1496
- */
1497
-
1498
- /**
1499
- * Register a custom email provider
1500
- *
1501
- * @param provider - Custom email provider implementation
1502
- *
1503
- * @example
1504
- * ```typescript
1505
- * import { registerEmailProvider } from '@spfn/auth/server/services/email';
1506
- *
1507
- * const sendgridProvider = {
1508
- * name: 'sendgrid',
1509
- * sendEmail: async (params) => {
1510
- * // SendGrid implementation
1511
- * return { success: true, messageId: '...' };
1512
- * }
1513
- * };
1514
- *
1515
- * registerEmailProvider(sendgridProvider);
1516
- * ```
1517
- */
1518
- declare function registerEmailProvider(provider: EmailProvider): void;
1519
- /**
1520
- * Send email using the registered provider
1521
- *
1522
- * Falls back to development mode (console only) if no provider is registered
1523
- *
1524
- * @param params - Email parameters
1525
- * @returns Send result
1526
- */
1527
- declare function sendEmail(params: SendEmailParams): Promise<SendEmailResult>;
1528
-
1529
- /**
1530
- * @spfn/auth - SMS Service Types
1531
- *
1532
- * Type definitions for SMS sending service
1533
- */
1534
- /**
1535
- * Parameters for sending SMS
1536
- */
1537
- interface SendSMSParams {
1538
- /**
1539
- * Phone number in E.164 format (e.g., +821012345678)
1540
- */
1541
- phone: string;
1542
- /**
1543
- * SMS message content
1544
- */
1545
- message: string;
1546
- /**
1547
- * Purpose of the SMS (for logging)
1548
- */
1549
- purpose?: string;
1550
- }
1551
- /**
1552
- * Result of sending SMS
1553
- */
1554
- interface SendSMSResult {
1555
- /**
1556
- * Whether SMS was sent successfully
1557
- */
1558
- success: boolean;
1559
- /**
1560
- * Message ID from SMS provider (if successful)
1561
- */
1562
- messageId?: string;
1563
- /**
1564
- * Error message (if failed)
1565
- */
1566
- error?: string;
1567
- }
1568
- /**
1569
- * SMS Provider Interface
1570
- *
1571
- * Implement this interface to create custom SMS providers
1572
- *
1573
- * @example
1574
- * ```typescript
1575
- * import { SMSProvider, registerSMSProvider } from '@spfn/auth/server/services/sms';
1576
- *
1577
- * const twilioProvider: SMSProvider = {
1578
- * name: 'twilio',
1579
- * sendSMS: async (params) => {
1580
- * // Your Twilio implementation
1581
- * return { success: true, messageId: '...' };
1582
- * }
1583
- * };
1584
- *
1585
- * registerSMSProvider(twilioProvider);
1586
- * ```
1587
- */
1588
- interface SMSProvider {
1589
- /**
1590
- * Provider name (e.g., 'aws-sns', 'twilio', 'custom')
1591
- */
1592
- name: string;
1593
- /**
1594
- * Send SMS via this provider
1595
- *
1596
- * @param params - SMS parameters
1597
- * @returns Send result
1598
- */
1599
- sendSMS(params: SendSMSParams): Promise<SendSMSResult>;
1600
- }
1601
-
1602
- /**
1603
- * @spfn/auth - SMS Provider Management
1604
- *
1605
- * Manages SMS provider registration and fallback behavior
1606
- */
1607
-
1608
- /**
1609
- * Register a custom SMS provider
1610
- *
1611
- * @param provider - Custom SMS provider implementation
1612
- *
1613
- * @example
1614
- * ```typescript
1615
- * import { registerSMSProvider } from '@spfn/auth/server/services/sms';
1616
- *
1617
- * const twilioProvider = {
1618
- * name: 'twilio',
1619
- * sendSMS: async (params) => {
1620
- * // Twilio implementation
1621
- * return { success: true, messageId: '...' };
1622
- * }
1623
- * };
1624
- *
1625
- * registerSMSProvider(twilioProvider);
1626
- * ```
1627
- */
1628
- declare function registerSMSProvider(provider: SMSProvider): void;
1629
- /**
1630
- * Send SMS using the registered provider
1631
- *
1632
- * Falls back to development mode (console only) if no provider is registered
1633
- *
1634
- * @param params - SMS parameters
1635
- * @returns Send result
1636
- */
1637
- declare function sendSMS(params: SendSMSParams): Promise<SendSMSResult>;
1328
+ declare function updateUserProfileService(userId: string | number | bigint, params: UpdateProfileParams): Promise<ProfileInfo>;
1638
1329
 
1639
1330
  /**
1640
1331
  * @spfn/auth - Database Schema Definition
@@ -4130,6 +3821,32 @@ declare class UserProfilesRepository extends BaseRepository {
4130
3821
  company: string | null;
4131
3822
  jobTitle: string | null;
4132
3823
  }>;
3824
+ /**
3825
+ * 프로필 Upsert (by User ID)
3826
+ *
3827
+ * 프로필이 없으면 생성, 있으면 업데이트
3828
+ * 새로 생성 시 displayName은 필수 (없으면 'User'로 설정)
3829
+ */
3830
+ upsertByUserId(userId: number, data: Partial<Omit<NewUserProfile, 'userId'>>): Promise<{
3831
+ userId: number;
3832
+ id: number;
3833
+ displayName: string;
3834
+ createdAt: Date;
3835
+ updatedAt: Date;
3836
+ metadata: Record<string, any> | null;
3837
+ firstName: string | null;
3838
+ lastName: string | null;
3839
+ avatarUrl: string | null;
3840
+ bio: string | null;
3841
+ locale: string | null;
3842
+ timezone: string | null;
3843
+ dateOfBirth: string | null;
3844
+ gender: string | null;
3845
+ website: string | null;
3846
+ location: string | null;
3847
+ company: string | null;
3848
+ jobTitle: string | null;
3849
+ }>;
4133
3850
  /**
4134
3851
  * User ID로 프로필 데이터 조회 (formatted)
4135
3852
  *
@@ -4148,6 +3865,7 @@ declare class UserProfilesRepository extends BaseRepository {
4148
3865
  location: string | null;
4149
3866
  company: string | null;
4150
3867
  jobTitle: string | null;
3868
+ metadata: Record<string, any> | null;
4151
3869
  createdAt: Date;
4152
3870
  updatedAt: Date;
4153
3871
  } | null>;
@@ -4422,6 +4140,136 @@ declare class InvitationsRepository extends BaseRepository {
4422
4140
  }
4423
4141
  declare const invitationsRepository: InvitationsRepository;
4424
4142
 
4143
+ /**
4144
+ * Social Accounts Repository
4145
+ *
4146
+ * OAuth 소셜 계정 데이터 관리를 위한 Repository
4147
+ * BaseRepository를 상속받아 자동 트랜잭션 컨텍스트 지원 및 Read/Write 분리
4148
+ */
4149
+
4150
+ /**
4151
+ * Social Accounts Repository 클래스
4152
+ */
4153
+ declare class SocialAccountsRepository extends BaseRepository {
4154
+ /**
4155
+ * provider와 providerUserId로 소셜 계정 조회
4156
+ * Read replica 사용
4157
+ */
4158
+ findByProviderAndProviderId(provider: SocialProvider, providerUserId: string): Promise<{
4159
+ createdAt: Date;
4160
+ updatedAt: Date;
4161
+ id: number;
4162
+ userId: number;
4163
+ provider: "google" | "github" | "kakao" | "naver";
4164
+ providerUserId: string;
4165
+ providerEmail: string | null;
4166
+ accessToken: string | null;
4167
+ refreshToken: string | null;
4168
+ tokenExpiresAt: Date | null;
4169
+ }>;
4170
+ /**
4171
+ * userId로 모든 소셜 계정 조회
4172
+ * Read replica 사용
4173
+ */
4174
+ findByUserId(userId: number): Promise<{
4175
+ createdAt: Date;
4176
+ updatedAt: Date;
4177
+ id: number;
4178
+ userId: number;
4179
+ provider: "google" | "github" | "kakao" | "naver";
4180
+ providerUserId: string;
4181
+ providerEmail: string | null;
4182
+ accessToken: string | null;
4183
+ refreshToken: string | null;
4184
+ tokenExpiresAt: Date | null;
4185
+ }[]>;
4186
+ /**
4187
+ * userId와 provider로 소셜 계정 조회
4188
+ * Read replica 사용
4189
+ */
4190
+ findByUserIdAndProvider(userId: number, provider: SocialProvider): Promise<{
4191
+ createdAt: Date;
4192
+ updatedAt: Date;
4193
+ id: number;
4194
+ userId: number;
4195
+ provider: "google" | "github" | "kakao" | "naver";
4196
+ providerUserId: string;
4197
+ providerEmail: string | null;
4198
+ accessToken: string | null;
4199
+ refreshToken: string | null;
4200
+ tokenExpiresAt: Date | null;
4201
+ }>;
4202
+ /**
4203
+ * 소셜 계정 생성
4204
+ * Write primary 사용
4205
+ */
4206
+ create(data: NewUserSocialAccount): Promise<{
4207
+ userId: number;
4208
+ id: number;
4209
+ createdAt: Date;
4210
+ updatedAt: Date;
4211
+ provider: "google" | "github" | "kakao" | "naver";
4212
+ providerUserId: string;
4213
+ providerEmail: string | null;
4214
+ accessToken: string | null;
4215
+ refreshToken: string | null;
4216
+ tokenExpiresAt: Date | null;
4217
+ }>;
4218
+ /**
4219
+ * 토큰 정보 업데이트
4220
+ * Write primary 사용
4221
+ */
4222
+ updateTokens(id: number, data: {
4223
+ accessToken?: string | null;
4224
+ refreshToken?: string | null;
4225
+ tokenExpiresAt?: Date | null;
4226
+ }): Promise<{
4227
+ createdAt: Date;
4228
+ updatedAt: Date;
4229
+ id: number;
4230
+ userId: number;
4231
+ provider: "google" | "github" | "kakao" | "naver";
4232
+ providerUserId: string;
4233
+ providerEmail: string | null;
4234
+ accessToken: string | null;
4235
+ refreshToken: string | null;
4236
+ tokenExpiresAt: Date | null;
4237
+ }>;
4238
+ /**
4239
+ * 소셜 계정 삭제
4240
+ * Write primary 사용
4241
+ */
4242
+ deleteById(id: number): Promise<{
4243
+ userId: number;
4244
+ id: number;
4245
+ createdAt: Date;
4246
+ updatedAt: Date;
4247
+ provider: "google" | "github" | "kakao" | "naver";
4248
+ providerUserId: string;
4249
+ providerEmail: string | null;
4250
+ accessToken: string | null;
4251
+ refreshToken: string | null;
4252
+ tokenExpiresAt: Date | null;
4253
+ }>;
4254
+ /**
4255
+ * userId와 provider로 소셜 계정 삭제
4256
+ * Write primary 사용
4257
+ */
4258
+ deleteByUserIdAndProvider(userId: number, provider: SocialProvider): Promise<{
4259
+ userId: number;
4260
+ id: number;
4261
+ createdAt: Date;
4262
+ updatedAt: Date;
4263
+ provider: "google" | "github" | "kakao" | "naver";
4264
+ providerUserId: string;
4265
+ providerEmail: string | null;
4266
+ accessToken: string | null;
4267
+ refreshToken: string | null;
4268
+ tokenExpiresAt: Date | null;
4269
+ }>;
4270
+ }
4271
+ declare const socialAccountsRepository: SocialAccountsRepository;
4272
+
4425
4273
  /**
4426
4274
  * @spfn/auth - Password Helpers
4427
4275
  *
@@ -4715,6 +4563,57 @@ declare const requireAnyPermission: _spfn_core_route.NamedMiddlewareFactory<"any
4715
4563
  */
4716
4564
  declare const requireRole: _spfn_core_route.NamedMiddlewareFactory<"role", string[]>;
4717
4565
 
4566
+ /**
4567
+ * @spfn/auth - Role Guard Middleware
4568
+ *
4569
+ * Middleware for role-based access control with allow/deny options
4570
+ */
4571
+ /**
4572
+ * Role guard options
4573
+ */
4574
+ interface RoleGuardOptions {
4575
+ /**
4576
+ * Roles to allow (OR condition)
4577
+ * User must have at least one of these roles
4578
+ */
4579
+ allow?: string[];
4580
+ /**
4581
+ * Roles to deny
4582
+ * User with any of these roles will be rejected
4583
+ */
4584
+ deny?: string[];
4585
+ }
4586
+ /**
4587
+ * Role-based access control middleware
4588
+ *
4589
+ * Must be used after authenticate middleware
4590
+ *
4591
+ * @param options - Role guard options (allow/deny)
4592
+ * @returns Middleware function
4593
+ *
4594
+ * @example Allow specific roles
4595
+ * ```typescript
4596
+ * export const adminRoute = route.get('/admin')
4597
+ * .use([authenticate, roleGuard({ allow: ['admin', 'superadmin'] })])
4598
+ * .handler(async (c) => { ... });
4599
+ * ```
4600
+ *
4601
+ * @example Deny specific roles
4602
+ * ```typescript
4603
+ * export const publicRoute = route.get('/content')
4604
+ * .use([authenticate, roleGuard({ deny: ['banned', 'suspended'] })])
4605
+ * .handler(async (c) => { ... });
4606
+ * ```
4607
+ *
4608
+ * @example Combined allow and deny
4609
+ * ```typescript
4610
+ * export const managerRoute = route.get('/manage')
4611
+ * .use([authenticate, roleGuard({ allow: ['admin', 'manager'], deny: ['suspended'] })])
4612
+ * .handler(async (c) => { ... });
4613
+ * ```
4614
+ */
4615
+ declare const roleGuard: _spfn_core_route.NamedMiddlewareFactory<"roleGuard", [options: RoleGuardOptions]>;
4616
+
4718
4617
  /**
4719
4618
  * Auth Context Helpers
4720
4619
  *
@@ -4917,6 +4816,8 @@ declare const COOKIE_NAMES: {
4917
4816
  readonly SESSION: "spfn_session";
4918
4817
  /** Current key ID (for key rotation) */
4919
4818
  readonly SESSION_KEY_ID: "spfn_session_key_id";
4819
+ /** Pending OAuth session (privateKey, keyId, algorithm) - temporary during OAuth flow */
4820
+ readonly OAUTH_PENDING: "spfn_oauth_pending";
4920
4821
  };
4921
4822
  /**
4922
4823
  * Parse duration string to seconds
@@ -4973,6 +4874,114 @@ declare function getAuthConfig(): AuthConfig;
4973
4874
  */
4974
4875
  declare function getSessionTtl(override?: string | number): number;
4975
4876
 
4877
+ /**
4878
+ * Google OAuth 2.0 Client
4879
+ *
4880
+ * Authorization Code Flow 구현
4881
+ * - getGoogleAuthUrl: Google 로그인 URL 생성
4882
+ * - exchangeCodeForTokens: Code를 Token으로 교환
4883
+ * - getGoogleUserInfo: 사용자 정보 조회
4884
+ */
4885
+ interface GoogleTokenResponse {
4886
+ access_token: string;
4887
+ expires_in: number;
4888
+ refresh_token?: string;
4889
+ scope: string;
4890
+ token_type: string;
4891
+ id_token?: string;
4892
+ }
4893
+ interface GoogleUserInfo {
4894
+ id: string;
4895
+ email: string;
4896
+ verified_email: boolean;
4897
+ name?: string;
4898
+ given_name?: string;
4899
+ family_name?: string;
4900
+ picture?: string;
4901
+ locale?: string;
4902
+ }
4903
+ /**
4904
+ * Google OAuth가 활성화되어 있는지 확인
4905
+ */
4906
+ declare function isGoogleOAuthEnabled(): boolean;
4907
+ /**
4908
+ * Google OAuth 설정 가져오기
4909
+ */
4910
+ declare function getGoogleOAuthConfig(): {
4911
+ clientId: string;
4912
+ clientSecret: string;
4913
+ redirectUri: string;
4914
+ };
4915
+ /**
4916
+ * Google 로그인 URL 생성
4917
+ *
4918
+ * @param state - CSRF 방지용 state 파라미터 (암호화된 returnUrl + nonce 포함)
4919
+ * @param scopes - 요청할 OAuth scopes (기본: env 또는 email, profile)
4920
+ */
4921
+ declare function getGoogleAuthUrl(state: string, scopes?: string[]): string;
4922
+ /**
4923
+ * Authorization Code를 Token으로 교환
4924
+ *
4925
+ * @param code - Google에서 받은 authorization code
4926
+ */
4927
+ declare function exchangeCodeForTokens(code: string): Promise<GoogleTokenResponse>;
4928
+ /**
4929
+ * Access Token으로 Google 사용자 정보 조회
4930
+ *
4931
+ * @param accessToken - Google access token
4932
+ */
4933
+ declare function getGoogleUserInfo(accessToken: string): Promise<GoogleUserInfo>;
4934
+ /**
4935
+ * Refresh Token으로 새 Access Token 획득
4936
+ *
4937
+ * @param refreshToken - Google refresh token
4938
+ */
4939
+ declare function refreshAccessToken(refreshToken: string): Promise<GoogleTokenResponse>;
4940
+
4941
+ /**
4942
+ * OAuth State Management
4943
+ *
4944
+ * CSRF 방지를 위한 state 파라미터 암호화/복호화
4945
+ * - returnUrl: OAuth 성공 후 리다이렉트할 URL
4946
+ * - nonce: CSRF 방지용 일회용 토큰
4947
+ * - provider: OAuth provider (google, github 등)
4948
+ * - publicKey, keyId, fingerprint, algorithm: 클라이언트 키 정보
4949
+ * - expiresAt: state 만료 시간
4950
+ */
4951
+
4952
+ interface OAuthState {
4953
+ returnUrl: string;
4954
+ nonce: string;
4955
+ provider: string;
4956
+ publicKey: string;
4957
+ keyId: string;
4958
+ fingerprint: string;
4959
+ algorithm: KeyAlgorithmType;
4960
+ }
4961
+ interface CreateOAuthStateParams {
4962
+ provider: string;
4963
+ returnUrl: string;
4964
+ publicKey: string;
4965
+ keyId: string;
4966
+ fingerprint: string;
4967
+ algorithm: KeyAlgorithmType;
4968
+ }
4969
+ /**
4970
+ * OAuth state 생성 및 암호화
4971
+ *
4972
+ * @param params - state 생성에 필요한 파라미터
4973
+ * @returns 암호화된 state 문자열
4974
+ */
4975
+ declare function createOAuthState(params: CreateOAuthStateParams): Promise<string>;
4976
+ /**
4977
+ * OAuth state 복호화 및 검증
4978
+ *
4979
+ * @param encryptedState - 암호화된 state 문자열
4980
+ * @returns 복호화된 state 객체
4981
+ * @throws Error if state is invalid or expired (JWE exp claim으로 자동 검증)
4982
+ */
4983
+ declare function verifyOAuthState(encryptedState: string): Promise<OAuthState>;
4984
+
4976
4985
  /**
4977
4986
  * @spfn/auth - Centralized Logger
4978
4987
  *
@@ -4985,6 +4994,7 @@ declare const authLogger: {
4985
4994
  general: _spfn_core_logger.Logger;
4986
4995
  login: _spfn_core_logger.Logger;
4987
4996
  keyRotation: _spfn_core_logger.Logger;
4997
+ oauth: _spfn_core_logger.Logger;
4988
4998
  };
4989
4999
  service: _spfn_core_logger.Logger;
4990
5000
  setup: _spfn_core_logger.Logger;
@@ -5068,4 +5078,61 @@ interface AuthLifecycleConfig {
5068
5078
  */
5069
5079
  declare function createAuthLifecycle(options?: AuthInitOptions): AuthLifecycleConfig;
5070
5080
 
5071
- export { type AuthConfig, AuthContext, COOKIE_NAMES, type EmailProvider, type EmailTemplateProvider, type EmailTemplateResult, type Invitation, InvitationStatus, InvitationsRepository, KeyAlgorithmType, type KeyPair, KeysRepository, 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 Permission, type PermissionEntity, PermissionsRepository, type Role, type RoleEntity, type RolePermission, RolePermissionsRepository, RolesRepository, type SMSProvider, type SendEmailParams, type SendEmailResult, type SendSMSParams, type SendSMSResult, type SessionData, type SessionPayload, type TokenPayload, type User, type UserPermission, UserPermissionsRepository, type UserProfile, UserProfilesRepository, type UserPublicKey, type UserSocialAccount, UsersRepository, type VerificationCode, type VerificationCodeParams, VerificationCodesRepository, VerificationPurpose, acceptInvitation, addPermissionToRole, authLogger, authSchema, cancelInvitation, configureAuth, createAuthLifecycle, createInvitation, createRole, decodeToken, deleteInvitation, deleteRole, expireOldInvitations, generateClientToken, generateKeyPair, generateKeyPairES256, generateKeyPairRS256, generateToken, getAllRoles, getAuth, getAuthConfig, getAuthSessionService, getInvitationByToken, getInvitationTemplate, getInvitationWithDetails, getKeyId, getKeySize, getPasswordResetTemplate, getRoleByName, getRolePermissions, getSessionInfo, getSessionTtl, getUser, getUserByEmailService, getUserByIdService, getUserByPhoneService, getUserId, getUserPermissions, getUserProfileService, getVerificationCodeTemplate, getWelcomeTemplate, hasAllPermissions, hasAnyPermission, hasAnyRole, hasPermission, hasRole, hashPassword, initializeAuth, invitationsRepository, keysRepository, listInvitations, parseDuration, permissions, permissionsRepository, registerEmailProvider, registerEmailTemplates, registerSMSProvider, removePermissionFromRole, requireAnyPermission, requirePermissions, requireRole, resendInvitation, rolePermissions, rolePermissionsRepository, roles, rolesRepository, sealSession, sendEmail, sendSMS, setRolePermissions, shouldRefreshSession, shouldRotateKey, unsealSession, updateLastLoginService, updateRole, updateUserService, userInvitations, userPermissions, userPermissionsRepository, userProfiles, userProfilesRepository, userPublicKeys, userSocialAccounts, users, usersRepository, validateInvitation, validatePasswordStrength, verificationCodes, verificationCodesRepository, verifyClientToken, verifyKeyFingerprint, verifyPassword, verifyToken };
5081
+ /**
5082
+ * @spfn/auth - Auth Events
5083
+ *
5084
+ * 인증 관련 이벤트 정의
5085
+ * - auth.login: 로그인 성공 시 (기존 사용자만)
5086
+ * - auth.register: 회원가입 성공 시 (OAuth 신규 가입 포함)
5087
+ */
5088
+ /**
5089
+ * Auth provider type
5090
+ */
5091
+ declare const AuthProviderSchema: _sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"email">, _sinclair_typebox.TLiteral<"phone">, _sinclair_typebox.TLiteral<"google">]>;
5092
+ /**
5093
+ * auth.login - 로그인 성공 이벤트
5094
+ *
5095
+ * 발행 시점:
5096
+ * - 이메일/전화 로그인 성공 시
5097
+ * - OAuth 기존 사용자 로그인 시
5098
+ *
5099
+ * @example
5100
+ * ```typescript
5101
+ * authLoginEvent.subscribe(async (payload) => {
5102
+ * await analytics.trackLogin(payload.userId, payload.provider);
5103
+ * });
5104
+ * ```
5105
+ */
5106
+ declare const authLoginEvent: _spfn_core_event.EventDef<{
5107
+ email?: string | undefined;
5108
+ phone?: string | undefined;
5109
+ userId: string;
5110
+ provider: "email" | "phone" | "google";
5111
+ }>;
5112
+ /**
5113
+ * auth.register - 회원가입 성공 이벤트
5114
+ *
5115
+ * 발행 시점:
5116
+ * - 이메일/전화 회원가입 성공 시
5117
+ * - OAuth 신규 사용자 가입 시
5118
+ *
5119
+ * @example
5120
+ * ```typescript
5121
+ * authRegisterEvent.subscribe(async (payload) => {
5122
+ * await emailService.sendWelcome(payload.email);
5123
+ * });
5124
+ * ```
5125
+ */
5126
+ declare const authRegisterEvent: _spfn_core_event.EventDef<{
5127
+ email?: string | undefined;
5128
+ phone?: string | undefined;
5129
+ userId: string;
5130
+ provider: "email" | "phone" | "google";
5131
+ }>;
5132
+ /**
5133
+ * Auth event payload types
5134
+ */
5135
+ type AuthLoginPayload = typeof authLoginEvent._payload;
5136
+ type AuthRegisterPayload = typeof authRegisterEvent._payload;
5137
+
5138
+ export { type AuthConfig, AuthContext, type AuthLoginPayload, AuthProviderSchema, type AuthRegisterPayload, COOKIE_NAMES, type CreateOAuthStateParams, type GoogleTokenResponse, type GoogleUserInfo, type Invitation, InvitationStatus, InvitationsRepository, KeyAlgorithmType, type KeyPair, KeysRepository, 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 SessionData, 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, authRegisterEvent, authSchema, cancelInvitation, 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, getRoleByName, getRolePermissions, getSessionInfo, getSessionTtl, getUser, getUserByEmailService, getUserByIdService, getUserByPhoneService, getUserId, getUserPermissions, getUserProfileService, getUserRole, hasAllPermissions, hasAnyPermission, hasAnyRole, hasPermission, hasRole, hashPassword, initializeAuth, invitationsRepository, isGoogleOAuthEnabled, keysRepository, listInvitations, parseDuration, permissions, permissionsRepository, refreshAccessToken, removePermissionFromRole, requireAnyPermission, requirePermissions, requireRole, resendInvitation, roleGuard, rolePermissions, rolePermissionsRepository, roles, rolesRepository, sealSession, setRolePermissions, shouldRefreshSession, shouldRotateKey, socialAccountsRepository, unsealSession, updateLastLoginService, updateRole, updateUserProfileService, updateUserService, userInvitations, userPermissions, userPermissionsRepository, userProfiles, userProfilesRepository, userPublicKeys, userSocialAccounts, users, usersRepository, validateInvitation, validatePasswordStrength, verificationCodes, verificationCodesRepository, verifyClientToken, verifyKeyFingerprint, verifyOAuthState, verifyPassword, verifyToken };