@crvouga/mockingbird-service-oauth 1.0.2 → 1.2.0

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/cli.js CHANGED
@@ -3,8 +3,8 @@ import {
3
3
  runCli,
4
4
  serveCommand,
5
5
  serveTarget
6
- } from "./chunk-X5QMVVR5.js";
7
- import "./chunk-I24F66FL.js";
6
+ } from "./chunk-U4WWQUOX.js";
7
+ import "./chunk-XUUSJ73W.js";
8
8
 
9
9
  // src/cli.ts
10
10
  var code = await runCli(
package/dist/index.d.ts CHANGED
@@ -518,7 +518,7 @@ type WebhookHub = {
518
518
  messages(namespace?: string): WebhookMessage[];
519
519
  deliveries(namespace?: string): WebhookDelivery[];
520
520
  replay(deliveryId: string): Promise<WebhookDelivery | undefined>;
521
- /** Run every pending retry (and release held reordered messages) now. */
521
+ /** Run every pending retry (and release held reordered messages) now, and every retry those attempts schedule, until nothing is pending. */
522
522
  flush(): Promise<void>;
523
523
  /** Resolve once nothing is in flight. */
524
524
  idle(): Promise<void>;
@@ -635,6 +635,10 @@ type OAuthBehavior = {
635
635
  refreshTtlSeconds?: number;
636
636
  refreshRotation?: "reuse" | "rotate";
637
637
  refreshError?: "invalid_grant" | "invalid_rapt";
638
+ /** Offsets an ID token's iat and auth_time from the mock clock; exp stays iat + accessTtlSeconds. */
639
+ idTokenClockSkewSeconds?: number;
640
+ /** "unpublished" signs ID tokens with a key no JWKS response ever contains. */
641
+ idTokenSigningKey?: "published" | "unpublished";
638
642
  };
639
643
  /** Additional scopes accepted for incremental/partial-consent tests. No resource APIs implied. */
640
644
  additionalScopes?: string[];
@@ -727,6 +731,21 @@ declare const OAUTH_SCENARIOS: {
727
731
  readonly tokenUnavailable: 0.25;
728
732
  };
729
733
  };
734
+ readonly id_token_clock_ahead: {
735
+ readonly tokens: {
736
+ readonly idTokenClockSkewSeconds: 600;
737
+ };
738
+ };
739
+ readonly id_token_stale: {
740
+ readonly tokens: {
741
+ readonly idTokenClockSkewSeconds: -7200;
742
+ };
743
+ };
744
+ readonly id_token_unknown_key: {
745
+ readonly tokens: {
746
+ readonly idTokenSigningKey: "unpublished";
747
+ };
748
+ };
730
749
  };
731
750
  type OAuthScenario = keyof typeof OAUTH_SCENARIOS;
732
751
  type BehaviorInput = OAuthBehavior & {
@@ -807,8 +826,19 @@ type Client = {
807
826
  teamId: string;
808
827
  keyId: string;
809
828
  publicKey: JsonWebKey;
829
+ /** Where Sign in with Apple server-to-server notifications are POSTed. */
830
+ notificationUrl?: string;
810
831
  };
811
832
  };
833
+ type AppleNotificationType = "consent-revoked" | "account-delete" | "email-disabled" | "email-enabled";
834
+ /** Outcome of one server-to-server notification; a failed delivery never throws. */
835
+ type NotificationDelivery = {
836
+ clientId: string;
837
+ type: AppleNotificationType;
838
+ delivered: boolean;
839
+ status?: number;
840
+ error?: string;
841
+ };
812
842
 
813
843
  /**
814
844
  * The slice of OpenAPI 3.1 (and JSON Schema 2020-12) Mockingbird understands.
@@ -1032,6 +1062,10 @@ type OAuthAPIOptions = APIOptions & {
1032
1062
  seed?: number | string;
1033
1063
  /** CSP nonce source for form-post responses. Defaults to `crypto.randomUUID`. */
1034
1064
  nonce?: () => string;
1065
+ /** Outbound delivery of Sign in with Apple server-to-server notifications. Defaults to global `fetch`. */
1066
+ webhooks?: {
1067
+ fetch?: (request: Request) => Promise<Response>;
1068
+ };
1035
1069
  };
1036
1070
  /** Portable OAuth/OIDC provider. State is isolated and included in runtime snapshots. */
1037
1071
  declare class OAuthAPI {
@@ -1045,6 +1079,8 @@ declare class OAuthAPI {
1045
1079
  private readonly consents;
1046
1080
  private signer;
1047
1081
  private previousSigners;
1082
+ /** Never published: signs ID tokens for `tokens.idTokenSigningKey: "unpublished"`. */
1083
+ private unpublishedSigner?;
1048
1084
  readonly behavior: BehaviorState;
1049
1085
  private readonly identities;
1050
1086
  private readonly appleDisclosures;
@@ -1058,12 +1094,31 @@ declare class OAuthAPI {
1058
1094
  seedAccount(account: Account): Account;
1059
1095
  registerClient(client: Client): Client;
1060
1096
  reset(): Promise<void>;
1061
- private issuer;
1097
+ issuer(request: Request): string;
1062
1098
  configureBehavior(input: BehaviorInput): OAuthBehavior;
1063
1099
  rotateSigningKey(retainPrevious?: boolean): {
1064
1100
  kid: string;
1065
1101
  };
1066
- revokeConsent(clientId: string, accountId: string): void;
1102
+ /**
1103
+ * Withdraws one client's consent. When the client registered `apple.notificationUrl` and held
1104
+ * the consent, Apple's `consent-revoked` notification is delivered before this resolves.
1105
+ */
1106
+ revokeConsent(clientId: string, accountId: string, issuer?: string): Promise<NotificationDelivery[]>;
1107
+ /**
1108
+ * Deletes an account with its grants and sessions, after telling every client that held a
1109
+ * consent (`account-delete`).
1110
+ */
1111
+ deleteAccount(accountId: string, issuer?: string): Promise<NotificationDelivery[]>;
1112
+ /**
1113
+ * Tells every client whose identity for the account is a private relay address that the user
1114
+ * turned forwarding off (`email-disabled`) or on (`email-enabled`).
1115
+ */
1116
+ setRelayForwarding(accountId: string, forwarding: boolean, issuer?: string): Promise<NotificationDelivery[]>;
1117
+ /** Clients with a notification endpoint that hold a consent for the account. */
1118
+ private notifiable;
1119
+ private notify;
1120
+ /** Drops one client's grant for an account: consent, identity, first-use disclosure, codes, tokens. */
1121
+ private forget;
1067
1122
  private paths;
1068
1123
  private supportedScopes;
1069
1124
  private identityKey;
@@ -1077,6 +1132,7 @@ declare class OAuthAPI {
1077
1132
  private authorize;
1078
1133
  private consent;
1079
1134
  private interact;
1135
+ private startSession;
1080
1136
  private finish;
1081
1137
  private callback;
1082
1138
  private githubTokenResponse;
@@ -1084,4 +1140,4 @@ declare class OAuthAPI {
1084
1140
  }
1085
1141
 
1086
1142
  export { OAUTH_PRESETS, OAUTH_SCENARIOS, OAuthAPI, createMultiRuntime, createRuntime, document, operationIds, supportedOperationIds };
1087
- export type { Account, BehaviorEvent, BehaviorInput, Client, EdgeCase, OAuthAPIOptions, OAuthBehavior, OAuthMount, OAuthMultiRuntime, OAuthMultiRuntimeOptions, OAuthRuntime, OAuthRuntimeOptions, OAuthScenario, Provider };
1143
+ export type { Account, AppleNotificationType, BehaviorEvent, BehaviorInput, Client, EdgeCase, NotificationDelivery, OAuthAPIOptions, OAuthBehavior, OAuthMount, OAuthMultiRuntime, OAuthMultiRuntimeOptions, OAuthRuntime, OAuthRuntimeOptions, OAuthScenario, Provider };
package/dist/index.js CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  document,
8
8
  operationIds,
9
9
  supportedOperationIds
10
- } from "./chunk-I24F66FL.js";
10
+ } from "./chunk-XUUSJ73W.js";
11
11
  export {
12
12
  OAUTH_PRESETS,
13
13
  OAUTH_SCENARIOS,
package/dist/server.d.ts CHANGED
@@ -458,7 +458,7 @@ type WebhookHub$1 = {
458
458
  messages(namespace?: string): WebhookMessage$1[];
459
459
  deliveries(namespace?: string): WebhookDelivery$1[];
460
460
  replay(deliveryId: string): Promise<WebhookDelivery$1 | undefined>;
461
- /** Run every pending retry (and release held reordered messages) now. */
461
+ /** Run every pending retry (and release held reordered messages) now, and every retry those attempts schedule, until nothing is pending. */
462
462
  flush(): Promise<void>;
463
463
  /** Resolve once nothing is in flight. */
464
464
  idle(): Promise<void>;
@@ -1057,7 +1057,7 @@ type WebhookHub = {
1057
1057
  messages(namespace?: string): WebhookMessage[];
1058
1058
  deliveries(namespace?: string): WebhookDelivery[];
1059
1059
  replay(deliveryId: string): Promise<WebhookDelivery | undefined>;
1060
- /** Run every pending retry (and release held reordered messages) now. */
1060
+ /** Run every pending retry (and release held reordered messages) now, and every retry those attempts schedule, until nothing is pending. */
1061
1061
  flush(): Promise<void>;
1062
1062
  /** Resolve once nothing is in flight. */
1063
1063
  idle(): Promise<void>;
@@ -1174,6 +1174,10 @@ type OAuthBehavior = {
1174
1174
  refreshTtlSeconds?: number;
1175
1175
  refreshRotation?: "reuse" | "rotate";
1176
1176
  refreshError?: "invalid_grant" | "invalid_rapt";
1177
+ /** Offsets an ID token's iat and auth_time from the mock clock; exp stays iat + accessTtlSeconds. */
1178
+ idTokenClockSkewSeconds?: number;
1179
+ /** "unpublished" signs ID tokens with a key no JWKS response ever contains. */
1180
+ idTokenSigningKey?: "published" | "unpublished";
1177
1181
  };
1178
1182
  /** Additional scopes accepted for incremental/partial-consent tests. No resource APIs implied. */
1179
1183
  additionalScopes?: string[];
@@ -1266,6 +1270,21 @@ declare const OAUTH_SCENARIOS: {
1266
1270
  readonly tokenUnavailable: 0.25;
1267
1271
  };
1268
1272
  };
1273
+ readonly id_token_clock_ahead: {
1274
+ readonly tokens: {
1275
+ readonly idTokenClockSkewSeconds: 600;
1276
+ };
1277
+ };
1278
+ readonly id_token_stale: {
1279
+ readonly tokens: {
1280
+ readonly idTokenClockSkewSeconds: -7200;
1281
+ };
1282
+ };
1283
+ readonly id_token_unknown_key: {
1284
+ readonly tokens: {
1285
+ readonly idTokenSigningKey: "unpublished";
1286
+ };
1287
+ };
1269
1288
  };
1270
1289
  type OAuthScenario = keyof typeof OAUTH_SCENARIOS;
1271
1290
  type BehaviorInput = OAuthBehavior & {
@@ -1346,8 +1365,19 @@ type Client = {
1346
1365
  teamId: string;
1347
1366
  keyId: string;
1348
1367
  publicKey: JsonWebKey;
1368
+ /** Where Sign in with Apple server-to-server notifications are POSTed. */
1369
+ notificationUrl?: string;
1349
1370
  };
1350
1371
  };
1372
+ type AppleNotificationType = "consent-revoked" | "account-delete" | "email-disabled" | "email-enabled";
1373
+ /** Outcome of one server-to-server notification; a failed delivery never throws. */
1374
+ type NotificationDelivery = {
1375
+ clientId: string;
1376
+ type: AppleNotificationType;
1377
+ delivered: boolean;
1378
+ status?: number;
1379
+ error?: string;
1380
+ };
1351
1381
 
1352
1382
  type OAuthAPIOptions = APIOptions & {
1353
1383
  /** Browser Fetch forbids Cookie/Set-Cookie; local transports may explicitly remap them. */
@@ -1368,6 +1398,10 @@ type OAuthAPIOptions = APIOptions & {
1368
1398
  seed?: number | string;
1369
1399
  /** CSP nonce source for form-post responses. Defaults to `crypto.randomUUID`. */
1370
1400
  nonce?: () => string;
1401
+ /** Outbound delivery of Sign in with Apple server-to-server notifications. Defaults to global `fetch`. */
1402
+ webhooks?: {
1403
+ fetch?: (request: Request) => Promise<Response>;
1404
+ };
1371
1405
  };
1372
1406
  /** Portable OAuth/OIDC provider. State is isolated and included in runtime snapshots. */
1373
1407
  declare class OAuthAPI {
@@ -1381,6 +1415,8 @@ declare class OAuthAPI {
1381
1415
  private readonly consents;
1382
1416
  private signer;
1383
1417
  private previousSigners;
1418
+ /** Never published: signs ID tokens for `tokens.idTokenSigningKey: "unpublished"`. */
1419
+ private unpublishedSigner?;
1384
1420
  readonly behavior: BehaviorState;
1385
1421
  private readonly identities;
1386
1422
  private readonly appleDisclosures;
@@ -1394,12 +1430,31 @@ declare class OAuthAPI {
1394
1430
  seedAccount(account: Account): Account;
1395
1431
  registerClient(client: Client): Client;
1396
1432
  reset(): Promise<void>;
1397
- private issuer;
1433
+ issuer(request: Request): string;
1398
1434
  configureBehavior(input: BehaviorInput): OAuthBehavior;
1399
1435
  rotateSigningKey(retainPrevious?: boolean): {
1400
1436
  kid: string;
1401
1437
  };
1402
- revokeConsent(clientId: string, accountId: string): void;
1438
+ /**
1439
+ * Withdraws one client's consent. When the client registered `apple.notificationUrl` and held
1440
+ * the consent, Apple's `consent-revoked` notification is delivered before this resolves.
1441
+ */
1442
+ revokeConsent(clientId: string, accountId: string, issuer?: string): Promise<NotificationDelivery[]>;
1443
+ /**
1444
+ * Deletes an account with its grants and sessions, after telling every client that held a
1445
+ * consent (`account-delete`).
1446
+ */
1447
+ deleteAccount(accountId: string, issuer?: string): Promise<NotificationDelivery[]>;
1448
+ /**
1449
+ * Tells every client whose identity for the account is a private relay address that the user
1450
+ * turned forwarding off (`email-disabled`) or on (`email-enabled`).
1451
+ */
1452
+ setRelayForwarding(accountId: string, forwarding: boolean, issuer?: string): Promise<NotificationDelivery[]>;
1453
+ /** Clients with a notification endpoint that hold a consent for the account. */
1454
+ private notifiable;
1455
+ private notify;
1456
+ /** Drops one client's grant for an account: consent, identity, first-use disclosure, codes, tokens. */
1457
+ private forget;
1403
1458
  private paths;
1404
1459
  private supportedScopes;
1405
1460
  private identityKey;
@@ -1413,6 +1468,7 @@ declare class OAuthAPI {
1413
1468
  private authorize;
1414
1469
  private consent;
1415
1470
  private interact;
1471
+ private startSession;
1416
1472
  private finish;
1417
1473
  private callback;
1418
1474
  private githubTokenResponse;
package/dist/server.js CHANGED
@@ -3,8 +3,8 @@ import {
3
3
  createMultiServer,
4
4
  createServer,
5
5
  serveTarget
6
- } from "./chunk-X5QMVVR5.js";
7
- import "./chunk-I24F66FL.js";
6
+ } from "./chunk-U4WWQUOX.js";
7
+ import "./chunk-XUUSJ73W.js";
8
8
  export {
9
9
  DEFAULT_PORT,
10
10
  createMultiServer,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crvouga/mockingbird-service-oauth",
3
- "version": "1.0.2",
3
+ "version": "1.2.0",
4
4
  "description": "Portable social-login mock with Google, Apple, Microsoft, GitHub and generic OIDC profiles, private relay identities, reproducible edge cases, signed tokens and an accessible UI.",
5
5
  "license": "MIT",
6
6
  "type": "module",