@spfn/auth 0.3.0-beta.20 → 0.3.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/README.md +107 -3
- package/dist/client-proof.js +5 -3
- package/dist/client-proof.js.map +1 -1
- package/dist/config.d.ts +40 -0
- package/dist/config.js +19 -0
- package/dist/config.js.map +1 -1
- package/dist/errors.d.ts +28 -2
- package/dist/errors.js +12 -0
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +19 -2
- package/dist/index.js +21 -1
- package/dist/index.js.map +1 -1
- package/dist/{machine-principals-BD4tnASp.d.ts → machine-principals-B7N8gux0.d.ts} +355 -7
- package/dist/server.d.ts +506 -268
- package/dist/server.js +1405 -950
- package/dist/server.js.map +1 -1
- package/migrations/20260918142743_smart_cassandra_nova/migration.sql +2 -0
- package/migrations/20260918142743_smart_cassandra_nova/snapshot.json +5297 -0
- package/migrations/20260918143800_fat_princess_powerful/migration.sql +17 -0
- package/migrations/20260918143800_fat_princess_powerful/snapshot.json +5523 -0
- package/package.json +1 -1
|
@@ -5,6 +5,7 @@ import { K as KeyAlgorithmType, h as KeyPlatformType, j as SocialProvider } from
|
|
|
5
5
|
import * as _sinclair_typebox from '@sinclair/typebox';
|
|
6
6
|
import { Static } from '@sinclair/typebox';
|
|
7
7
|
import * as drizzle_orm_pg_core from 'drizzle-orm/pg-core';
|
|
8
|
+
import * as _spfn_core_event from '@spfn/core/event';
|
|
8
9
|
import { Context } from 'hono';
|
|
9
10
|
import { User } from '@spfn/auth/server';
|
|
10
11
|
|
|
@@ -107,6 +108,10 @@ interface RegisterParams {
|
|
|
107
108
|
deviceName?: string;
|
|
108
109
|
platform?: KeyPlatformType;
|
|
109
110
|
metadata?: Record<string, unknown>;
|
|
111
|
+
/** Client address of the request, from `deviceProvenance` at the route. */
|
|
112
|
+
ip?: string;
|
|
113
|
+
/** `user-agent` of the request, already truncated at the route. */
|
|
114
|
+
userAgent?: string;
|
|
110
115
|
}
|
|
111
116
|
interface RegisterResult {
|
|
112
117
|
userId: string;
|
|
@@ -125,6 +130,10 @@ interface LoginParams {
|
|
|
125
130
|
algorithm?: KeyAlgorithmType;
|
|
126
131
|
deviceName?: string;
|
|
127
132
|
platform?: KeyPlatformType;
|
|
133
|
+
/** Client address of the request, from `deviceProvenance` at the route. */
|
|
134
|
+
ip?: string;
|
|
135
|
+
/** `user-agent` of the request, already truncated at the route. */
|
|
136
|
+
userAgent?: string;
|
|
128
137
|
}
|
|
129
138
|
interface LoginResult {
|
|
130
139
|
userId: string;
|
|
@@ -351,6 +360,10 @@ interface CompleteSignupParams {
|
|
|
351
360
|
deviceName?: string;
|
|
352
361
|
platform?: KeyPlatformType;
|
|
353
362
|
metadata?: Record<string, unknown>;
|
|
363
|
+
/** Client address of the request, from `deviceProvenance` at the route. */
|
|
364
|
+
ip?: string;
|
|
365
|
+
/** `user-agent` of the request, already truncated at the route. */
|
|
366
|
+
userAgent?: string;
|
|
354
367
|
}
|
|
355
368
|
/**
|
|
356
369
|
* Step 3 — set the password, which is what creates the account.
|
|
@@ -446,6 +459,10 @@ interface CompletePasswordResetParams {
|
|
|
446
459
|
algorithm?: KeyAlgorithmType;
|
|
447
460
|
deviceName?: string;
|
|
448
461
|
platform?: KeyPlatformType;
|
|
462
|
+
/** Client address of the request, from `deviceProvenance` at the route. */
|
|
463
|
+
ip?: string;
|
|
464
|
+
/** `user-agent` of the request, already truncated at the route. */
|
|
465
|
+
userAgent?: string;
|
|
449
466
|
}
|
|
450
467
|
/**
|
|
451
468
|
* Step 3 — set the new password, which is what completes the reset.
|
|
@@ -530,6 +547,10 @@ interface DenyDeviceAuthParams {
|
|
|
530
547
|
}
|
|
531
548
|
interface PollDeviceAuthParams {
|
|
532
549
|
deviceCode: string;
|
|
550
|
+
/** Client address of the request, from `deviceProvenance` at the route. */
|
|
551
|
+
ip?: string;
|
|
552
|
+
/** `user-agent` of the request, already truncated at the route. */
|
|
553
|
+
userAgent?: string;
|
|
533
554
|
}
|
|
534
555
|
/** Nobody has answered yet. Not an error — the waiting device waits. */
|
|
535
556
|
interface DeviceAuthPendingResult {
|
|
@@ -975,6 +996,10 @@ interface FinishPasskeyLoginParams {
|
|
|
975
996
|
oldKeyId?: string;
|
|
976
997
|
deviceName?: string;
|
|
977
998
|
platform?: KeyPlatformType;
|
|
999
|
+
/** Client address of the request, from `deviceProvenance` at the route. */
|
|
1000
|
+
ip?: string;
|
|
1001
|
+
/** `user-agent` of the request, already truncated at the route. */
|
|
1002
|
+
userAgent?: string;
|
|
978
1003
|
}
|
|
979
1004
|
/**
|
|
980
1005
|
* Step 2 of sign-in — verify the assertion, then sign in exactly as a password
|
|
@@ -1031,6 +1056,264 @@ declare function revokePasskeyService(params: RevokePasskeyParams): Promise<{
|
|
|
1031
1056
|
passkeyId: string;
|
|
1032
1057
|
}>;
|
|
1033
1058
|
|
|
1059
|
+
/**
|
|
1060
|
+
* Auth provider type
|
|
1061
|
+
*
|
|
1062
|
+
* 직접 인증(email/phone) + 등록 가능한 모든 소셜 provider(SOCIAL_PROVIDERS).
|
|
1063
|
+
*/
|
|
1064
|
+
declare const AuthProviderSchema: _sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"email">, _sinclair_typebox.TLiteral<"phone">, ..._sinclair_typebox.TLiteral<"google" | "apple" | "github" | "kakao" | "naver" | "superself">[]]>;
|
|
1065
|
+
/**
|
|
1066
|
+
* auth.login - 로그인 성공 이벤트
|
|
1067
|
+
*
|
|
1068
|
+
* 발행 시점:
|
|
1069
|
+
* - 이메일/전화 로그인 성공 시
|
|
1070
|
+
* - OAuth 기존 사용자 로그인 시
|
|
1071
|
+
* - 기기 코드 승인이 소비되어 새 기기 키가 등록될 때 (provider: 'device')
|
|
1072
|
+
*
|
|
1073
|
+
* @example
|
|
1074
|
+
* ```typescript
|
|
1075
|
+
* authLoginEvent.subscribe(async (payload) => {
|
|
1076
|
+
* await analytics.trackLogin(payload.userId, payload.provider);
|
|
1077
|
+
* });
|
|
1078
|
+
* ```
|
|
1079
|
+
*/
|
|
1080
|
+
declare const authLoginEvent: _spfn_core_event.EventDef<{
|
|
1081
|
+
email?: string | undefined;
|
|
1082
|
+
phone?: string | undefined;
|
|
1083
|
+
userId: string;
|
|
1084
|
+
provider: "email" | "phone" | "google" | "apple" | "github" | "kakao" | "naver" | "superself" | "device" | "passkey";
|
|
1085
|
+
}>;
|
|
1086
|
+
/**
|
|
1087
|
+
* Where a device key was registered — the door the new device came through.
|
|
1088
|
+
*
|
|
1089
|
+
* Required on `RegisterPublicKeyParams` rather than optional with a default: a
|
|
1090
|
+
* new *call site* for key registration must choose one, and a default would let
|
|
1091
|
+
* it inherit somebody else's answer silently. `'register'` and `'signup-link'`
|
|
1092
|
+
* both arrive at `createVerifiedAccount`, so the two name themselves there;
|
|
1093
|
+
* `'invitation'` is the one path that stores a key without the key service.
|
|
1094
|
+
*/
|
|
1095
|
+
declare const DeviceRegistrationChannelSchema: _sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"register">, _sinclair_typebox.TLiteral<"signup-link">, _sinclair_typebox.TLiteral<"invitation">, _sinclair_typebox.TLiteral<"password">, _sinclair_typebox.TLiteral<"oauth">, _sinclair_typebox.TLiteral<"oauth-native">, _sinclair_typebox.TLiteral<"device-code">, _sinclair_typebox.TLiteral<"password-reset">, _sinclair_typebox.TLiteral<"passkey">]>;
|
|
1096
|
+
/** The nine doors a device key is registered through. */
|
|
1097
|
+
type DeviceRegistrationChannel = Static<typeof DeviceRegistrationChannelSchema>;
|
|
1098
|
+
/**
|
|
1099
|
+
* auth.device.registered — a new device key was added to an account
|
|
1100
|
+
*
|
|
1101
|
+
* 발행 시점:
|
|
1102
|
+
* - a key row was created for an account and the transaction that created it
|
|
1103
|
+
* committed, on every one of the nine channels above
|
|
1104
|
+
*
|
|
1105
|
+
* This is the notice an account owner needs and could not get before: a stolen
|
|
1106
|
+
* password used to sign in on a new device was silent, because a login event
|
|
1107
|
+
* says a session began and not what it began on. Rotation is deliberately not
|
|
1108
|
+
* announced — replacing the key of a device that is already signed in is not a
|
|
1109
|
+
* new device, and a notice for it would train the owner to ignore the ones that
|
|
1110
|
+
* matter.
|
|
1111
|
+
*
|
|
1112
|
+
* `ip` and `userAgent` are what the registering request said about itself. Both
|
|
1113
|
+
* are unauthenticated display material: nothing is decided by them, and a field
|
|
1114
|
+
* is absent rather than carrying a placeholder when the request resolved none.
|
|
1115
|
+
*
|
|
1116
|
+
* Neither the full fingerprint nor the public key is carried. The prefix is
|
|
1117
|
+
* enough to point at one entry of `listKeys`, which is what a notice needs.
|
|
1118
|
+
*
|
|
1119
|
+
* @example
|
|
1120
|
+
* ```typescript
|
|
1121
|
+
* authDeviceRegisteredEvent.subscribe(async ({ userId, deviceName, ip, channel }) => {
|
|
1122
|
+
* await notifyOwner(userId, `A new device signed in (${deviceName ?? channel})`);
|
|
1123
|
+
* });
|
|
1124
|
+
* ```
|
|
1125
|
+
*/
|
|
1126
|
+
declare const authDeviceRegisteredEvent: _spfn_core_event.EventDef<{
|
|
1127
|
+
deviceName?: string | undefined;
|
|
1128
|
+
platform?: string | undefined;
|
|
1129
|
+
ip?: string | undefined;
|
|
1130
|
+
userAgent?: string | undefined;
|
|
1131
|
+
keyId: string;
|
|
1132
|
+
algorithm: string;
|
|
1133
|
+
userId: string;
|
|
1134
|
+
fingerprintPrefix: string;
|
|
1135
|
+
createdAtMillis: number;
|
|
1136
|
+
channel: "password" | "register" | "oauth-native" | "oauth" | "invitation" | "signup-link" | "password-reset" | "passkey" | "device-code";
|
|
1137
|
+
}>;
|
|
1138
|
+
/**
|
|
1139
|
+
* auth.register - 회원가입 성공 이벤트
|
|
1140
|
+
*
|
|
1141
|
+
* 발행 시점:
|
|
1142
|
+
* - 이메일/전화 회원가입 성공 시
|
|
1143
|
+
* - OAuth 신규 사용자 가입 시
|
|
1144
|
+
*
|
|
1145
|
+
* @example
|
|
1146
|
+
* ```typescript
|
|
1147
|
+
* authRegisterEvent.subscribe(async (payload) => {
|
|
1148
|
+
* await emailService.sendWelcome(payload.email);
|
|
1149
|
+
* });
|
|
1150
|
+
* ```
|
|
1151
|
+
*/
|
|
1152
|
+
declare const authRegisterEvent: _spfn_core_event.EventDef<{
|
|
1153
|
+
email?: string | undefined;
|
|
1154
|
+
phone?: string | undefined;
|
|
1155
|
+
metadata?: {
|
|
1156
|
+
[x: string]: unknown;
|
|
1157
|
+
} | undefined;
|
|
1158
|
+
userId: string;
|
|
1159
|
+
provider: "email" | "phone" | "google" | "apple" | "github" | "kakao" | "naver" | "superself";
|
|
1160
|
+
}>;
|
|
1161
|
+
/**
|
|
1162
|
+
* auth.invitation.created - 초대 생성 이벤트
|
|
1163
|
+
*
|
|
1164
|
+
* 발행 시점:
|
|
1165
|
+
* - createInvitation() 성공 시
|
|
1166
|
+
* - resendInvitation() 성공 시
|
|
1167
|
+
*
|
|
1168
|
+
* @example
|
|
1169
|
+
* ```typescript
|
|
1170
|
+
* invitationCreatedEvent.subscribe(async (payload) => {
|
|
1171
|
+
* const inviteUrl = `${APP_URL}/invite/${payload.token}`;
|
|
1172
|
+
* await notificationService.send({
|
|
1173
|
+
* channel: 'email',
|
|
1174
|
+
* to: payload.email,
|
|
1175
|
+
* subject: 'You are invited!',
|
|
1176
|
+
* html: renderInviteEmail({ inviteUrl, ...payload.metadata }),
|
|
1177
|
+
* });
|
|
1178
|
+
* });
|
|
1179
|
+
* ```
|
|
1180
|
+
*/
|
|
1181
|
+
declare const invitationCreatedEvent: _spfn_core_event.EventDef<{
|
|
1182
|
+
metadata?: {
|
|
1183
|
+
[x: string]: unknown;
|
|
1184
|
+
} | undefined;
|
|
1185
|
+
email: string;
|
|
1186
|
+
token: string;
|
|
1187
|
+
expiresAt: string;
|
|
1188
|
+
roleId: number;
|
|
1189
|
+
invitedBy: string;
|
|
1190
|
+
invitationId: string;
|
|
1191
|
+
isResend: boolean;
|
|
1192
|
+
}>;
|
|
1193
|
+
/**
|
|
1194
|
+
* auth.invitation.accepted - 초대 수락 이벤트
|
|
1195
|
+
*
|
|
1196
|
+
* 발행 시점:
|
|
1197
|
+
* - acceptInvitation() 성공 시
|
|
1198
|
+
*
|
|
1199
|
+
* @example
|
|
1200
|
+
* ```typescript
|
|
1201
|
+
* invitationAcceptedEvent.subscribe(async (payload) => {
|
|
1202
|
+
* await onboardingService.start(payload.userId);
|
|
1203
|
+
* });
|
|
1204
|
+
* ```
|
|
1205
|
+
*/
|
|
1206
|
+
declare const invitationAcceptedEvent: _spfn_core_event.EventDef<{
|
|
1207
|
+
metadata?: {
|
|
1208
|
+
[x: string]: unknown;
|
|
1209
|
+
} | undefined;
|
|
1210
|
+
email: string;
|
|
1211
|
+
userId: string;
|
|
1212
|
+
roleId: number;
|
|
1213
|
+
invitedBy: string;
|
|
1214
|
+
invitationId: string;
|
|
1215
|
+
}>;
|
|
1216
|
+
/**
|
|
1217
|
+
* auth.deletion.requested - 계정 탈퇴 요청 이벤트
|
|
1218
|
+
*
|
|
1219
|
+
* 발행 시점:
|
|
1220
|
+
* - requestAccountDeletionService() 성공 시 (self/admin 공통)
|
|
1221
|
+
*
|
|
1222
|
+
* @example
|
|
1223
|
+
* ```typescript
|
|
1224
|
+
* authDeletionRequestedEvent.subscribe(async (payload) => {
|
|
1225
|
+
* await analytics.trackChurnRisk(payload.userId);
|
|
1226
|
+
* });
|
|
1227
|
+
* ```
|
|
1228
|
+
*/
|
|
1229
|
+
declare const authDeletionRequestedEvent: _spfn_core_event.EventDef<{
|
|
1230
|
+
userId: string;
|
|
1231
|
+
purgeScheduledAt: string;
|
|
1232
|
+
userPublicId: string;
|
|
1233
|
+
requestedBy: "admin" | "self";
|
|
1234
|
+
}>;
|
|
1235
|
+
/**
|
|
1236
|
+
* auth.deletion.cancelled - 계정 탈퇴 복구 이벤트
|
|
1237
|
+
*
|
|
1238
|
+
* 발행 시점:
|
|
1239
|
+
* - cancelAccountDeletionService() 성공 시 (유예 기간 내 복구)
|
|
1240
|
+
*/
|
|
1241
|
+
declare const authDeletionCancelledEvent: _spfn_core_event.EventDef<{
|
|
1242
|
+
userId: string;
|
|
1243
|
+
userPublicId: string;
|
|
1244
|
+
}>;
|
|
1245
|
+
/**
|
|
1246
|
+
* auth.deletion.completed - 계정 파기 완료 이벤트
|
|
1247
|
+
*
|
|
1248
|
+
* 발행 시점:
|
|
1249
|
+
* - purge job(또는 즉시 파기 경로)이 유저를 파기한 직후
|
|
1250
|
+
*
|
|
1251
|
+
* PII를 담지 않는다 — userId(내부 순번)/email/phone 없이 userPublicId만 실어
|
|
1252
|
+
* 파기 완료 이후에도 구독자가 식별 정보를 다시 축적하지 않도록 한다.
|
|
1253
|
+
*/
|
|
1254
|
+
declare const authDeletionCompletedEvent: _spfn_core_event.EventDef<{
|
|
1255
|
+
userPublicId: string;
|
|
1256
|
+
purgeStrategy: "anonymize" | "hard-delete";
|
|
1257
|
+
}>;
|
|
1258
|
+
/**
|
|
1259
|
+
* auth.oauth.unlinked - provider발 연동 해제 이벤트
|
|
1260
|
+
*
|
|
1261
|
+
* 발행 시점:
|
|
1262
|
+
* - provider(카카오·네이버 등)가 unlink-notify 웹훅으로 연동 해제를 알려와
|
|
1263
|
+
* 소셜 계정 연결과 저장 토큰이 삭제된 직후
|
|
1264
|
+
*
|
|
1265
|
+
* 연결 삭제까지는 프레임워크가 수행하고, 그 이후(계정 탈퇴로 이어갈지 등)는
|
|
1266
|
+
* 앱 정책이므로 이 이벤트를 구독해 처리한다.
|
|
1267
|
+
*
|
|
1268
|
+
* @example
|
|
1269
|
+
* ```typescript
|
|
1270
|
+
* oauthUnlinkedEvent.subscribe(async (payload) => {
|
|
1271
|
+
* await requestAccountDeletionService({ userId: payload.userId, requestedBy: 'self' });
|
|
1272
|
+
* });
|
|
1273
|
+
* ```
|
|
1274
|
+
*/
|
|
1275
|
+
declare const oauthUnlinkedEvent: _spfn_core_event.EventDef<{
|
|
1276
|
+
reason?: string | undefined;
|
|
1277
|
+
userId: string;
|
|
1278
|
+
provider: "email" | "phone" | "google" | "apple" | "github" | "kakao" | "naver" | "superself";
|
|
1279
|
+
providerUserId: string;
|
|
1280
|
+
}>;
|
|
1281
|
+
/**
|
|
1282
|
+
* auth.password.reset — an account's password was replaced through a reset link
|
|
1283
|
+
*
|
|
1284
|
+
* 발행 시점:
|
|
1285
|
+
* - completePasswordResetService()가 커밋된 직후
|
|
1286
|
+
*
|
|
1287
|
+
* Distinct from a password *change*, which is made from a session that already
|
|
1288
|
+
* proved itself. This one is made by whoever opened a link in a mailbox, so it
|
|
1289
|
+
* is the event an app hangs a "your password was reset" notice on — and the
|
|
1290
|
+
* signal to look at, if the owner says they did not ask for it.
|
|
1291
|
+
*
|
|
1292
|
+
* @example
|
|
1293
|
+
* ```typescript
|
|
1294
|
+
* authPasswordResetEvent.subscribe(async (payload) => {
|
|
1295
|
+
* await notifyOwner(payload.userId, 'Your password was reset');
|
|
1296
|
+
* });
|
|
1297
|
+
* ```
|
|
1298
|
+
*/
|
|
1299
|
+
declare const authPasswordResetEvent: _spfn_core_event.EventDef<{
|
|
1300
|
+
email: string;
|
|
1301
|
+
userId: string;
|
|
1302
|
+
}>;
|
|
1303
|
+
/**
|
|
1304
|
+
* Auth event payload types
|
|
1305
|
+
*/
|
|
1306
|
+
type AuthLoginPayload = typeof authLoginEvent._payload;
|
|
1307
|
+
type AuthRegisterPayload = typeof authRegisterEvent._payload;
|
|
1308
|
+
type AuthPasswordResetPayload = typeof authPasswordResetEvent._payload;
|
|
1309
|
+
type AuthDeviceRegisteredPayload = typeof authDeviceRegisteredEvent._payload;
|
|
1310
|
+
type InvitationCreatedPayload = typeof invitationCreatedEvent._payload;
|
|
1311
|
+
type InvitationAcceptedPayload = typeof invitationAcceptedEvent._payload;
|
|
1312
|
+
type AuthDeletionRequestedPayload = typeof authDeletionRequestedEvent._payload;
|
|
1313
|
+
type AuthDeletionCancelledPayload = typeof authDeletionCancelledEvent._payload;
|
|
1314
|
+
type AuthDeletionCompletedPayload = typeof authDeletionCompletedEvent._payload;
|
|
1315
|
+
type OAuthUnlinkedPayload = typeof oauthUnlinkedEvent._payload;
|
|
1316
|
+
|
|
1034
1317
|
/**
|
|
1035
1318
|
* @spfn/auth - Key Service
|
|
1036
1319
|
*
|
|
@@ -1046,6 +1329,26 @@ interface RegisterPublicKeyParams {
|
|
|
1046
1329
|
/** Device label for the key list. Display only — nothing is authorized by it. */
|
|
1047
1330
|
deviceName?: string;
|
|
1048
1331
|
platform?: KeyPlatformType;
|
|
1332
|
+
/**
|
|
1333
|
+
* Which door this device came through. Required, so that a registration path
|
|
1334
|
+
* added later has to say what it is rather than inherit an answer.
|
|
1335
|
+
*/
|
|
1336
|
+
channel: DeviceRegistrationChannel;
|
|
1337
|
+
/** Client address of the registering request, absent when none resolved. */
|
|
1338
|
+
ip?: string;
|
|
1339
|
+
/** `user-agent` of the registering request, already truncated. */
|
|
1340
|
+
userAgent?: string;
|
|
1341
|
+
/**
|
|
1342
|
+
* The key this one replaces on the same device, when a revocation actually
|
|
1343
|
+
* happened. Its presence is what makes this a rotation rather than a new
|
|
1344
|
+
* device, so no event is announced for it.
|
|
1345
|
+
*
|
|
1346
|
+
* Only ever set from a `revokeKeyService` that returned true: an `oldKeyId`
|
|
1347
|
+
* naming somebody else's key, an already-revoked key or nothing at all
|
|
1348
|
+
* revokes nothing, and treating that as a rotation would be a way to
|
|
1349
|
+
* register a device with the owner's notice switched off.
|
|
1350
|
+
*/
|
|
1351
|
+
replacesKeyId?: string;
|
|
1049
1352
|
}
|
|
1050
1353
|
interface RotateKeyParams {
|
|
1051
1354
|
userId: number;
|
|
@@ -1069,8 +1372,17 @@ interface RevokeKeyParams {
|
|
|
1069
1372
|
}
|
|
1070
1373
|
interface RevokeAllKeysParams {
|
|
1071
1374
|
userId: number;
|
|
1072
|
-
/**
|
|
1073
|
-
|
|
1375
|
+
/**
|
|
1376
|
+
* The key the request itself is signed with — spared unless includeCurrent.
|
|
1377
|
+
*
|
|
1378
|
+
* Optional because the two branches have different needs and always did: the
|
|
1379
|
+
* sparing branch has to know what to spare, and the `includeCurrent` branch
|
|
1380
|
+
* never reads it. The signed revoke-all link is the caller with no current
|
|
1381
|
+
* key to name — it arrives with no session at all — and requiring a value it
|
|
1382
|
+
* would have to invent is how a claim about a device that made no request
|
|
1383
|
+
* gets into a result.
|
|
1384
|
+
*/
|
|
1385
|
+
currentKeyId?: string;
|
|
1074
1386
|
/** true signs the caller out too. Default false: "my other devices". */
|
|
1075
1387
|
includeCurrent?: boolean;
|
|
1076
1388
|
reason: string;
|
|
@@ -1105,6 +1417,15 @@ interface KeySummary {
|
|
|
1105
1417
|
isActive: boolean;
|
|
1106
1418
|
/** When it was revoked, for the "what did I cut off, and when" reading. */
|
|
1107
1419
|
revokedAtMillis?: number;
|
|
1420
|
+
/**
|
|
1421
|
+
* Client address the key was registered from, absent when none was resolved
|
|
1422
|
+
* or the key predates the column. Registration only — it does not move when
|
|
1423
|
+
* the device authenticates from somewhere else, which is what makes it
|
|
1424
|
+
* useful for recognising a device that was never yours.
|
|
1425
|
+
*/
|
|
1426
|
+
registeredIp?: string;
|
|
1427
|
+
/** `user-agent` of the registering request, on the same terms as above. */
|
|
1428
|
+
registeredUserAgent?: string;
|
|
1108
1429
|
}
|
|
1109
1430
|
interface ListKeysParams {
|
|
1110
1431
|
userId: number;
|
|
@@ -1136,10 +1457,13 @@ declare function rotateKeyService(params: RotateKeyParams): Promise<RotateKeyRes
|
|
|
1136
1457
|
/**
|
|
1137
1458
|
* Revoke a user's public key.
|
|
1138
1459
|
*
|
|
1139
|
-
* Returns false when
|
|
1140
|
-
*
|
|
1141
|
-
*
|
|
1142
|
-
*
|
|
1460
|
+
* Returns false when this call revoked nothing: the key belongs to somebody
|
|
1461
|
+
* else, or it was already revoked, or there is no such key. A caller acting on
|
|
1462
|
+
* a key id from outside (the device list) can therefore answer "not found"
|
|
1463
|
+
* instead of reporting a revocation that never happened — and the login paths
|
|
1464
|
+
* can tell a device replacement from a brand-new device, which is what decides
|
|
1465
|
+
* whether the owner is told about it. The repository scopes the update by
|
|
1466
|
+
* userId, so someone else's key is never touched either way.
|
|
1143
1467
|
*/
|
|
1144
1468
|
declare function revokeKeyService(params: RevokeKeyParams): Promise<boolean>;
|
|
1145
1469
|
/**
|
|
@@ -1476,6 +1800,10 @@ interface OAuthCallbackParams {
|
|
|
1476
1800
|
* an empty array when absent; verification then fails closed.
|
|
1477
1801
|
*/
|
|
1478
1802
|
expectedNonce: string | string[] | undefined;
|
|
1803
|
+
/** Client address of the callback request, from `deviceProvenance` at the route. */
|
|
1804
|
+
ip?: string;
|
|
1805
|
+
/** `user-agent` of the callback request, already truncated at the route. */
|
|
1806
|
+
userAgent?: string;
|
|
1479
1807
|
}
|
|
1480
1808
|
interface OAuthCallbackResult {
|
|
1481
1809
|
redirectUrl: string;
|
|
@@ -1573,6 +1901,10 @@ interface OAuthNativeParams {
|
|
|
1573
1901
|
* id_token이 담은 정보만으로 신원을 정규화한다.
|
|
1574
1902
|
*/
|
|
1575
1903
|
accessToken?: string;
|
|
1904
|
+
/** Client address of the request, from `deviceProvenance` at the route. */
|
|
1905
|
+
ip?: string;
|
|
1906
|
+
/** `user-agent` of the request, already truncated at the route. */
|
|
1907
|
+
userAgent?: string;
|
|
1576
1908
|
/** Apple은 첫 로그인에만 이름을 별도로 주므로 클라이언트가 전달할 수 있다. */
|
|
1577
1909
|
profile?: {
|
|
1578
1910
|
name?: string;
|
|
@@ -1971,6 +2303,21 @@ declare const mainAuthRouter: _spfn_core_route.Router<{
|
|
|
1971
2303
|
includeCurrent: _sinclair_typebox.TOptional<_sinclair_typebox.TBoolean>;
|
|
1972
2304
|
}>;
|
|
1973
2305
|
}, {}, RevokeAllKeysResult>;
|
|
2306
|
+
confirmRevokeAllLink: _spfn_core_route.RouteDef<{
|
|
2307
|
+
body: _sinclair_typebox.TObject<{
|
|
2308
|
+
token: _sinclair_typebox.TString;
|
|
2309
|
+
}>;
|
|
2310
|
+
}, {}, {
|
|
2311
|
+
expiresAt: string;
|
|
2312
|
+
activeKeyCount: number;
|
|
2313
|
+
}>;
|
|
2314
|
+
consumeRevokeAllLink: _spfn_core_route.RouteDef<{
|
|
2315
|
+
body: _sinclair_typebox.TObject<{
|
|
2316
|
+
token: _sinclair_typebox.TString;
|
|
2317
|
+
}>;
|
|
2318
|
+
}, {}, {
|
|
2319
|
+
revokedCount: number;
|
|
2320
|
+
}>;
|
|
1974
2321
|
changePassword: _spfn_core_route.RouteDef<{
|
|
1975
2322
|
body: _sinclair_typebox.TObject<{
|
|
1976
2323
|
currentPassword: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
|
|
@@ -2272,6 +2619,7 @@ declare const mainAuthRouter: _spfn_core_route.Router<{
|
|
|
2272
2619
|
status: "active" | "inactive" | "suspended" | "pending_deletion" | "deleted";
|
|
2273
2620
|
emailVerifiedAt: Date | null;
|
|
2274
2621
|
phoneVerifiedAt: Date | null;
|
|
2622
|
+
keyEpoch: number;
|
|
2275
2623
|
lastLoginAt: Date | null;
|
|
2276
2624
|
}>;
|
|
2277
2625
|
updateLocale: _spfn_core_route.RouteDef<{
|
|
@@ -2736,4 +3084,4 @@ declare const machineAuth: _spfn_core_route.NamedMiddleware<"machineAuth">;
|
|
|
2736
3084
|
*/
|
|
2737
3085
|
declare const requireMachineScope: _spfn_core_route.NamedMiddlewareFactory<"machineScope", string[]>;
|
|
2738
3086
|
|
|
2739
|
-
export { type
|
|
3087
|
+
export { type DenyDeviceAuthParams as $, type AuthInitOptions as A, type AuthDeletionRequestedPayload as B, type ConfirmSignupLinkResult as C, type DeviceAuthInfoResult as D, type AuthDeviceRegisteredPayload as E, type FinishPasskeyEnrollmentResult as F, type AuthLoginPayload as G, type AuthPasswordResetPayload as H, type IssueOneTimeTokenResult as I, type AuthProfileOutcome as J, type KeySummary as K, type LoginResult as L, type AuthProfileVerifier as M, type NewPasskey as N, type OAuthStartResult as O, type PermissionConfig as P, AuthProviderSchema as Q, type RoleConfig as R, type SendVerificationCodeResult as S, type AuthRegisterPayload as T, type UserProfile as U, VERIFICATION_PURPOSES as V, type ChangePasswordParams as W, type CompletePasswordResetParams as X, type CompleteSignupParams as Y, type ConfirmPasswordResetParams as Z, type ConfirmSignupLinkParams as _, type RegisterResult as a, assertRecentAuthentication as a$, type DeviceAuthApprovedResult as a0, type DeviceAuthInfoParams as a1, type DeviceAuthPendingResult as a2, DeviceAuthPollResponseSchema as a3, DeviceNameSchema as a4, type DeviceRegistrationChannel as a5, EmailSchema as a6, FingerprintSchema as a7, type FinishPasskeyEnrollmentParams as a8, type FinishPasskeyLoginParams as a9, type PollDeviceAuthResult as aA, PublicKeySchema as aB, type RecentAuthenticationParams as aC, type RegisterParams as aD, type RegisterPublicKeyParams as aE, type RenamePasskeyParams as aF, type RequestPasswordResetParams as aG, type RequestSignupLinkParams as aH, type RevokeAllKeysParams as aI, type RevokeKeyParams as aJ, type RevokePasskeyParams as aK, type RotateKeyParams as aL, type SendVerificationCodeParams as aM, type StartDeviceAuthParams as aN, type StartPasskeyEnrollmentParams as aO, TargetTypeSchema as aP, type UnlinkNotification as aQ, UnlinkNotifyRejection as aR, type UnlinkNotifyRequest as aS, type UnlinkNotifyResult as aT, UserCodeSchema as aU, VerificationPurposeSchema as aV, type VerifyCodeParams as aW, type VerifyCodeResult as aX, approveDeviceAuthService as aY, approveOAuth2AuthorizeService as aZ, assertNotLastRecoveryCredential as a_, type InvitationAcceptedPayload as aa, type InvitationCreatedPayload as ab, KEY_FINGERPRINT_PREFIX_LENGTH as ac, KeyIdSchema as ad, type LoginParams as ae, type LogoutParams as af, type MachinePrincipal as ag, type MachineVerifierRegistration as ah, type NativeVerifyOptions as ai, type NormalizedIdentity as aj, type OAuth2AuthorizeParams as ak, type OAuth2ScopeDescription as al, type OAuthCallbackParams as am, type OAuthCallbackResult as an, type OAuthCodeExchangeOptions as ao, type OAuthNativeParams as ap, type OAuthStartParams as aq, type OAuthTokens as ar, type OAuthUnlinkedPayload as as, PASSKEY_DEVICE_TYPES as at, PASSKEY_LABEL_MAX_LENGTH as au, type PasskeyDeviceType as av, PasswordSchema as aw, PhoneSchema as ax, PlatformSchema as ay, type PollDeviceAuthParams as az, type RequestSignupLinkResult as b, startDeviceAuthService as b$, authDeletionCancelledEvent as b0, authDeletionCompletedEvent as b1, authDeletionRequestedEvent as b2, authDeviceRegisteredEvent as b3, authLoginEvent as b4, authPasswordResetEvent as b5, authRegisterEvent as b6, authenticate as b7, buildOAuthErrorUrl as b8, changePasswordService as b9, oauthNativeService as bA, oauthStartService as bB, oauthUnlinkNotifyService as bC, oauthUnlinkedEvent as bD, optionalAuth as bE, passkeys as bF, pollDeviceAuthService as bG, registerAuthProfile as bH, registerMachineVerifier as bI, registerOAuthProvider as bJ, registerPublicKeyService as bK, registerService as bL, renamePasskeyService as bM, requestPasswordResetService as bN, requestSignupLinkService as bO, requireEnabledProvider as bP, requireMachineScope as bQ, resolveAuthenticatedUser as bR, revokeAllKeysService as bS, revokeAllOAuth2GrantsForUser as bT, revokeKeyService as bU, revokeOAuth2GrantService as bV, revokePasskeyService as bW, rotateKeyService as bX, runAuthProfile as bY, selectAuthProfile as bZ, sendVerificationCodeService as b_, completePasswordResetService as ba, completeSignupService as bb, confirmPasswordResetService as bc, confirmSignupLinkService as bd, denyDeviceAuthService as be, denyOAuth2AuthorizeService as bf, describeOAuth2AuthorizeRequestService as bg, finishPasskeyEnrollmentService as bh, finishPasskeyLoginService as bi, getDeviceAuthInfoService as bj, getEnabledOAuthProviders as bk, getGoogleAccessToken as bl, getMachinePrincipal as bm, getOAuthProvider as bn, getRegisteredProviders as bo, invitationAcceptedEvent as bp, invitationCreatedEvent as bq, isOAuthProviderEnabled as br, issueOneTimeTokenService as bs, listKeysService as bt, listOAuth2GrantsService as bu, listPasskeysService as bv, loginService as bw, logoutService as bx, machineAuth as by, oauthCallbackService as bz, type RequestPasswordResetResult as c, startPasskeyEnrollmentService as c0, startPasskeyLoginService as c1, verifyCodeService as c2, verifyOneTimeTokenService as c3, type ConfirmPasswordResetResult as d, type StartDeviceAuthResult as e, type PasskeySummary as f, type RotateKeyResult as g, type RevokeAllKeysResult as h, type OAuthNativeResult as i, type ProfileInfo as j, type OAuth2ConsentView as k, type OAuth2AuthorizationCodeIssued as l, mainAuthRouter as m, type OAuth2GrantSummary as n, type AuthSession as o, PERMISSION_CATEGORIES as p, type PermissionCategory as q, VERIFICATION_TARGET_TYPES as r, type VerificationPurpose as s, type VerificationTargetType as t, type OAuthProvider as u, type Passkey as v, type AuthContext as w, type ApproveDeviceAuthParams as x, type AuthDeletionCancelledPayload as y, type AuthDeletionCompletedPayload as z };
|