@crvouga/mockingbird-service-oauth 1.0.1 → 1.1.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/CHANGELOG.md CHANGED
@@ -1,6 +1,26 @@
1
1
  # Changelog — @crvouga/mockingbird-service-oauth
2
2
 
3
- ## 1.0.1 (2026-09-26)
3
+ ## 1.1.0 (2026-09-29)
4
+
5
+ ### Features
6
+
7
+ - stable data-testid hooks on the chooser, signup, consent and form_post pages ([43f687a](https://github.com/crvouga/mockingbird/commit/43f687afc421c9f9e96d1b60760622261ae110df))
8
+ - let a scalar naming a later branch's enum value pick that branch ([30ade3a](https://github.com/crvouga/mockingbird/commit/30ade3a28a5b6b273ffbf261216b821acac8e961))
9
+
10
+ ### Fixes and improvements
11
+
12
+ - skip Google consent after the account chooser when scopes were already granted ([1b0d62a](https://github.com/crvouga/mockingbird/commit/1b0d62a7b14e870138952f17c40ba2b6e1384ddf))
13
+ - stop cleared webhook deliveries from rescheduling forever ([424b78f](https://github.com/crvouga/mockingbird/commit/424b78f29317b162e3bf7d0049cc19be5b977026))
14
+ - serialize immediate webhook attempts to fix reorder flake ([625c82b](https://github.com/crvouga/mockingbird/commit/625c82b5a8a7992c1cf93e9df68e77af08b353e3))
15
+ - flush drains webhook retries scheduled while it runs ([c58cede](https://github.com/crvouga/mockingbird/commit/c58cede1b6ba7ae5ed3f8721ad9b7cd7bc0b1ca7))
16
+
17
+ ## 1.0.2 (2026-09-25)
18
+
19
+ ### Fixes and improvements
20
+
21
+ - treat enum [""] branches as unset markers in form coercion ([7177835](https://github.com/crvouga/mockingbird/commit/7177835cc510e14245d6648ad2821daa694bb80c))
22
+
23
+ ## 1.0.1 (2026-09-25)
4
24
 
5
25
  ### Fixes and improvements
6
26
 
package/README.md CHANGED
@@ -97,7 +97,7 @@ For the CLI, put the same `mounts` array in a JSON file and run `npx mockingbird
97
97
 
98
98
  ### Accounts and signup
99
99
 
100
- The chooser displays seeded, enabled test accounts. Choosing an account opens explicit consent; creating an account validates the email/name, rejects duplicate email addresses, persists the identity and opens the same consent flow. This is intentionally passwordless test identity selection; never use real passwords or personal data.
100
+ The chooser displays seeded, enabled test accounts. Choosing an account opens explicit consent (Google skips it when that account already granted every requested scope to the client; `prompt=consent` or a new scope asks again); creating an account validates the email/name, rejects duplicate email addresses, persists the identity and opens the same consent flow. This is intentionally passwordless test identity selection; never use real passwords or personal data.
101
101
 
102
102
  ```sh
103
103
  curl http://localhost:8810/__admin/clients -H 'content-type: application/json' \
@@ -109,6 +109,35 @@ curl http://localhost:8810/__admin/accounts
109
109
 
110
110
  Set `adminKey` (CLI `--admin-key`) to require `x-mockingbird-admin-key`. Programmatically, `runtime.instance().seedAccount(account)` inserts or updates a stable subject; `registerClient(client)` inserts or updates a client. Accounts support `emailVerified`, `picture`, `givenName`, `familyName`, `locale`, `hostedDomain`, `privateEmail`, `relayEmail`, `omitEmail`, `omitName` and `disabled`. Apple fixtures also accept `realUserStatus` (`0`, `1`, or `2`) and `transferSub` for risk and app-transfer claim tests. Microsoft fixtures accept `preferredUsername`, `tenantId`, `objectId`; GitHub fixtures accept `github: { id, login, publicEmail, emails }`. An email-list entry contains `email`, `primary`, `verified` and `visibility` (`public`, `private` or `null`).
111
111
 
112
+ ### Test hooks on the interaction pages
113
+
114
+ The chooser, signup, consent, `form_post` and error pages carry stable `data-testid` hooks, so a UI
115
+ suite (Playwright's `getByTestId`, a driver that selects only by test id) can drive them without CSS
116
+ classes or visible copy. The ids are part of the documented surface and do not change between versions.
117
+ Each page has exactly one root (the page's card), and every interactive element has its own id.
118
+
119
+ | Page | Element | `data-testid` |
120
+ | --- | --- | --- |
121
+ | chooser | page root | `oauth-mock-chooser` |
122
+ | chooser | one wrapper per account (shared id, with `data-account-id` and `data-email`) | `oauth-mock-account` |
123
+ | chooser | each account's button, unique per account | `oauth-mock-account-<account id>` |
124
+ | chooser | "Create a new account" | `oauth-mock-create-account` |
125
+ | chooser | "Choose an available account" error (`role="alert"`) | `oauth-mock-chooser-error` |
126
+ | chooser, signup, consent | cancel / deny button | `oauth-mock-deny` |
127
+ | signup | page root | `oauth-mock-signup` |
128
+ | signup | full name / email inputs | `oauth-mock-signup-name`, `oauth-mock-signup-email` |
129
+ | signup | submit button | `oauth-mock-signup-submit` |
130
+ | signup | validation or duplicate-email error (`role="alert"`) | `oauth-mock-signup-error` |
131
+ | consent | page root | `oauth-mock-consent` |
132
+ | consent | Allow button | `oauth-mock-allow` |
133
+ | consent (Apple, default `emailMode: "choose"`) | Share / Hide My Email radios | `oauth-mock-share-email`, `oauth-mock-hide-email` |
134
+ | `form_post` | page root (the hand-off page) | `oauth-mock-form-post` |
135
+ | `form_post` | no-JavaScript Continue button inside the `#callback` form | `oauth-mock-form-post-continue` |
136
+ | expired or unknown sign-in | page root | `oauth-mock-error` |
137
+
138
+ `<account id>` is HTML-escaped. A driver that runs no page scripts finishes Sign in with Apple by
139
+ tapping `oauth-mock-form-post-continue`; with scripts, the page submits the form itself.
140
+
112
141
  ### Fidelity and lifecycle
113
142
 
114
143
  - Authorization-code flow with exact redirect matching, including explicitly registered private-use URI schemes for native apps, state and nonce; duplicate parameters rejected. Invalid clients/callbacks never redirect. Public native clients require S256 PKCE.
@@ -2,7 +2,7 @@ import {
2
2
  OAUTH_SCENARIOS,
3
3
  createMultiRuntime,
4
4
  createRuntime
5
- } from "./chunk-I24F66FL.js";
5
+ } from "./chunk-JA62N2QU.js";
6
6
 
7
7
  // src/server.ts
8
8
  import { readFile as readFile2 } from "node:fs/promises";
@@ -377,4 +377,4 @@ export {
377
377
  createMultiServer,
378
378
  serveTarget
379
379
  };
380
- //# sourceMappingURL=chunk-X5QMVVR5.js.map
380
+ //# sourceMappingURL=chunk-FZKITSDL.js.map
@@ -1384,7 +1384,7 @@ var restoreNamespace = (sqlite, namespace, snapshot) => {
1384
1384
  };
1385
1385
 
1386
1386
  // ../core/dist/version.js
1387
- var PACKAGE_VERSION = true ? "1.0.1" : UNRELEASED_VERSION;
1387
+ var PACKAGE_VERSION = true ? "1.1.0" : UNRELEASED_VERSION;
1388
1388
 
1389
1389
  // ../core/dist/webhooks.js
1390
1390
  var json2 = (status, body) => new Response(JSON.stringify(body), { status, headers: { "content-type": "application/json" } });
@@ -2322,9 +2322,9 @@ var style = `
2322
2322
  .theme{border:0;padding:0;display:flex;gap:16px;align-items:center}.theme legend{float:left;margin-right:16px;padding:0}.theme label{display:flex;align-items:center;gap:5px;margin:0;font-weight:400;font-size:12px}.theme input{width:14px;height:14px;min-height:0;margin:0;padding:0;accent-color:var(--accent)}
2323
2323
 
2324
2324
  `;
2325
- function page(title, body, status = 200, action = "'self'", nonce = crypto.randomUUID()) {
2325
+ function page(title, body, status = 200, action = "'self'", nonce = crypto.randomUUID(), testId = "") {
2326
2326
  return new Response(
2327
- `<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="color-scheme" content="light dark"><title>${escapeHtml(title)} \xB7 OAuth Mock</title><style nonce="${nonce}">${style}</style></head><body><a class="skip" href="#main">Skip to content</a><header><span>OAuth Mock</span></header><main id="main"><section class="card" aria-labelledby="title">${body}</section><p class="note">Test accounts only.</p></main><footer><fieldset class="theme"><legend>Appearance</legend><label><input type="radio" name="oauth-theme" value="system" checked>System</label><label><input type="radio" name="oauth-theme" value="light">Light</label><label><input type="radio" name="oauth-theme" value="dark">Dark</label></fieldset></footer><script nonce="${nonce}">(()=>{const root=document.documentElement;const inputs=document.querySelectorAll('input[name="oauth-theme"]');const apply=value=>{root.dataset.theme=value;for(const input of inputs)input.checked=input.value===value;try{sessionStorage.setItem('oauth-mock-theme',value)}catch{}};try{const saved=sessionStorage.getItem('oauth-mock-theme');if(['system','light','dark'].includes(saved))apply(saved)}catch{}for(const input of inputs)input.addEventListener('change',()=>apply(input.value))})()</script></body></html>`,
2327
+ `<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="color-scheme" content="light dark"><title>${escapeHtml(title)} \xB7 OAuth Mock</title><style nonce="${nonce}">${style}</style></head><body><a class="skip" href="#main">Skip to content</a><header><span>OAuth Mock</span></header><main id="main"><section class="card" aria-labelledby="title"${testId ? ` data-testid="${testId}"` : ""}>${body}</section><p class="note">Test accounts only.</p></main><footer><fieldset class="theme"><legend>Appearance</legend><label><input type="radio" name="oauth-theme" value="system" checked>System</label><label><input type="radio" name="oauth-theme" value="light">Light</label><label><input type="radio" name="oauth-theme" value="dark">Dark</label></fieldset></footer><script nonce="${nonce}">(()=>{const root=document.documentElement;const inputs=document.querySelectorAll('input[name="oauth-theme"]');const apply=value=>{root.dataset.theme=value;for(const input of inputs)input.checked=input.value===value;try{sessionStorage.setItem('oauth-mock-theme',value)}catch{}};try{const saved=sessionStorage.getItem('oauth-mock-theme');if(['system','light','dark'].includes(saved))apply(saved)}catch{}for(const input of inputs)input.addEventListener('change',()=>apply(input.value))})()</script></body></html>`,
2328
2328
  {
2329
2329
  status,
2330
2330
  headers: {
@@ -2340,13 +2340,15 @@ function page(title, body, status = 200, action = "'self'", nonce = crypto.rando
2340
2340
  function loginPage(transaction, client, accounts, base, action, signup = false, error = "") {
2341
2341
  const hidden = `<input type="hidden" name="transaction" value="${escapeHtml(transaction)}">`;
2342
2342
  const endpoint = escapeHtml(`${base}/interaction`);
2343
- const intro = `<span class="eyebrow">Sign in</span><h1 id="title">${signup ? "Create your account" : "Choose an account"}</h1><p>${signup ? "Create an account to continue to" : "Choose an account to continue to"}<br><span class="app">${escapeHtml(client)}</span></p>${error ? `<div class="error" role="alert">${escapeHtml(error)}</div>` : ""}`;
2344
- const body = signup ? `<form method="post" action="${endpoint}">${hidden}<input type="hidden" name="action" value="signup"><div class="fields"><label for="name">Full name</label><input id="name" name="name" autocomplete="name" required maxlength="120"><label for="email">Email address</label><input id="email" name="email" type="email" autocomplete="email" required maxlength="254" aria-describedby="email-help"><p id="email-help" class="note">Use a fictional address. No email will be sent.</p></div><button class="primary">Create account &amp; continue</button></form><a class="back" href="${endpoint}?transaction=${escapeHtml(transaction)}">Back to accounts</a>` : `<div class="accounts">${accounts.map((a) => `<form method="post" action="${endpoint}">${hidden}<input type="hidden" name="action" value="select"><button class="account" name="account" value="${escapeHtml(a.id)}"><span class="avatar" aria-hidden="true">${escapeHtml(a.name.slice(0, 1).toUpperCase())}</span><span class="identity"><strong>${escapeHtml(a.name)}</strong><small>${escapeHtml(a.email)}</small></span><span class="arrow" aria-hidden="true">\u2192</span></button></form>`).join("") || '<p class="empty">No accounts yet. Create your first test identity below.</p>'}</div><form method="get" action="${endpoint}">${hidden}<input type="hidden" name="screen" value="signup"><button class="secondary">\uFF0B Create a new account</button></form>`;
2343
+ const intro = `<span class="eyebrow">Sign in</span><h1 id="title">${signup ? "Create your account" : "Choose an account"}</h1><p>${signup ? "Create an account to continue to" : "Choose an account to continue to"}<br><span class="app">${escapeHtml(client)}</span></p>${error ? `<div class="error" role="alert" data-testid="oauth-mock-${signup ? "signup" : "chooser"}-error">${escapeHtml(error)}</div>` : ""}`;
2344
+ const body = signup ? `<form method="post" action="${endpoint}">${hidden}<input type="hidden" name="action" value="signup"><div class="fields"><label for="name">Full name</label><input id="name" name="name" data-testid="oauth-mock-signup-name" autocomplete="name" required maxlength="120"><label for="email">Email address</label><input id="email" name="email" data-testid="oauth-mock-signup-email" type="email" autocomplete="email" required maxlength="254" aria-describedby="email-help"><p id="email-help" class="note">Use a fictional address. No email will be sent.</p></div><button class="primary" data-testid="oauth-mock-signup-submit">Create account &amp; continue</button></form><a class="back" href="${endpoint}?transaction=${escapeHtml(transaction)}">Back to accounts</a>` : `<div class="accounts">${accounts.map((a) => `<form method="post" action="${endpoint}" data-testid="oauth-mock-account" data-account-id="${escapeHtml(a.id)}" data-email="${escapeHtml(a.email)}">${hidden}<input type="hidden" name="action" value="select"><button class="account" data-testid="oauth-mock-account-${escapeHtml(a.id)}" name="account" value="${escapeHtml(a.id)}"><span class="avatar" aria-hidden="true">${escapeHtml(a.name.slice(0, 1).toUpperCase())}</span><span class="identity"><strong>${escapeHtml(a.name)}</strong><small>${escapeHtml(a.email)}</small></span><span class="arrow" aria-hidden="true">\u2192</span></button></form>`).join("") || '<p class="empty">No accounts yet. Create your first test identity below.</p>'}</div><form method="get" action="${endpoint}">${hidden}<input type="hidden" name="screen" value="signup"><button class="secondary" data-testid="oauth-mock-create-account">\uFF0B Create a new account</button></form>`;
2345
2345
  return page(
2346
2346
  signup ? "Create account" : "Choose an account",
2347
- `${intro}${body}<div class="divider"></div><form method="post" action="${endpoint}">${hidden}<button class="secondary" name="action" value="deny">Cancel sign-in</button></form>`,
2347
+ `${intro}${body}<div class="divider"></div><form method="post" action="${endpoint}">${hidden}<button class="secondary" data-testid="oauth-mock-deny" name="action" value="deny">Cancel sign-in</button></form>`,
2348
2348
  error ? 400 : 200,
2349
- action
2349
+ action,
2350
+ void 0,
2351
+ signup ? "oauth-mock-signup" : "oauth-mock-chooser"
2350
2352
  );
2351
2353
  }
2352
2354
  function consentPage(transaction, client, account, scopes2, base, action, privacy) {
@@ -2357,21 +2359,23 @@ function consentPage(transaction, client, account, scopes2, base, action, privac
2357
2359
  name: "View your name",
2358
2360
  offline_access: "Stay connected when you\u2019re away"
2359
2361
  };
2360
- const privacyFields = privacy ? privacy.choice ? `<fieldset class="privacy"><legend>Choose what to share</legend><label><input type="radio" name="email_choice" value="share" ${!privacy.hideEmail ? "checked" : ""}><span>Share my email<small>Your app will receive ${escapeHtml(account.email)}.</small></span></label><label><input type="radio" name="email_choice" value="hide" ${privacy.hideEmail ? "checked" : ""}><span>Hide my email<small>Use a private relay address to keep your email private.</small></span></label></fieldset>` : `<p>${privacy.hideEmail ? "A private relay address will be shared with this app." : "Your email address will be shared with this app."}</p>` : "";
2362
+ const privacyFields = privacy ? privacy.choice ? `<fieldset class="privacy"><legend>Choose what to share</legend><label><input type="radio" name="email_choice" data-testid="oauth-mock-share-email" value="share" ${!privacy.hideEmail ? "checked" : ""}><span>Share my email<small>Your app will receive ${escapeHtml(account.email)}.</small></span></label><label><input type="radio" name="email_choice" data-testid="oauth-mock-hide-email" value="hide" ${privacy.hideEmail ? "checked" : ""}><span>Hide my email<small>Use a private relay address to keep your email private.</small></span></label></fieldset>` : `<p>${privacy.hideEmail ? "A private relay address will be shared with this app." : "Your email address will be shared with this app."}</p>` : "";
2361
2363
  return page(
2362
2364
  "Review access",
2363
2365
  `<span class="eyebrow">Permissions</span><h1 id="title">Review access</h1><p><span class="app">${escapeHtml(client)}</span> would like access to your account.</p><div class="account"><span class="avatar" aria-hidden="true">${escapeHtml(account.name.slice(0, 1))}</span><span class="identity"><strong>${escapeHtml(account.name)}</strong><small>${escapeHtml(account.email)}</small></span></div><ul class="permissions">${scopes2.split(" ").filter(Boolean).map(
2364
2366
  (s) => `<li><span class="check" aria-hidden="true">\u2713</span>${escapeHtml(labels[s] ?? s)}</li>`
2365
2367
  ).join(
2366
2368
  ""
2367
- )}</ul><p>You can cancel now without sharing anything.</p><form method="post" action="${escapeHtml(base)}/interaction"><input type="hidden" name="transaction" value="${escapeHtml(transaction)}">${privacyFields}<button class="primary" name="action" value="allow">Allow &amp; continue</button><button class="secondary" name="action" value="deny">Cancel</button></form>`,
2369
+ )}</ul><p>You can cancel now without sharing anything.</p><form method="post" action="${escapeHtml(base)}/interaction"><input type="hidden" name="transaction" value="${escapeHtml(transaction)}">${privacyFields}<button class="primary" data-testid="oauth-mock-allow" name="action" value="allow">Allow &amp; continue</button><button class="secondary" data-testid="oauth-mock-deny" name="action" value="deny">Cancel</button></form>`,
2368
2370
  200,
2369
- action
2371
+ action,
2372
+ void 0,
2373
+ "oauth-mock-consent"
2370
2374
  );
2371
2375
  }
2372
2376
 
2373
2377
  // src/generated/openapi.ts
2374
- var document = JSON.parse(`{"openapi":"3.1.0","info":{"title":"Mockingbird OAuth & Social Login","version":"1.0.0"},"paths":{"/.well-known/openid-configuration":{"get":{"operationId":"Discovery","summary":"Discovery","x-mockingbird":{"parity":{"enabled":true,"reason":"Google, Apple and Microsoft discovery metadata is checked against their public live endpoints by scripts/parity.ts."}},"responses":{"200":{"description":"200","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"302":{"description":"302","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"400","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"description":"401","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"403":{"description":"403","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"404","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"503":{"description":"503","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/jwks":{"get":{"operationId":"Jwks","summary":"Jwks","x-mockingbird":{"parity":{"enabled":false,"reason":"Interactive OAuth transactions are exercised by protocol and independent JOSE tests."}},"responses":{"200":{"description":"200","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"302":{"description":"302","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"400","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"description":"401","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"403":{"description":"403","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"404","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"503":{"description":"503","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/authorize":{"get":{"operationId":"Authorize","summary":"Authorize","x-mockingbird":{"parity":{"enabled":false,"reason":"Interactive OAuth transactions are exercised by protocol and independent JOSE tests."}},"responses":{"200":{"description":"200","content":{"text/html":{"schema":{"type":"string"}}}},"302":{"description":"302","content":{"text/html":{"schema":{"type":"string"}}}},"400":{"description":"400","content":{"text/html":{"schema":{"type":"string"}}}},"401":{"description":"401","content":{"text/html":{"schema":{"type":"string"}}}},"403":{"description":"403","content":{"text/html":{"schema":{"type":"string"}}}},"404":{"description":"404","content":{"text/html":{"schema":{"type":"string"}}}},"503":{"description":"503","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/interaction":{"get":{"operationId":"InteractionPage","summary":"InteractionPage","x-mockingbird":{"parity":{"enabled":false,"reason":"Interactive OAuth transactions are exercised by protocol and independent JOSE tests."}},"responses":{"200":{"description":"200","content":{"text/html":{"schema":{"type":"string"}}}},"302":{"description":"302","content":{"text/html":{"schema":{"type":"string"}}}},"400":{"description":"400","content":{"text/html":{"schema":{"type":"string"}}}},"401":{"description":"401","content":{"text/html":{"schema":{"type":"string"}}}},"403":{"description":"403","content":{"text/html":{"schema":{"type":"string"}}}},"404":{"description":"404","content":{"text/html":{"schema":{"type":"string"}}}},"503":{"description":"503","content":{"text/html":{"schema":{"type":"string"}}}}}},"post":{"operationId":"Interact","summary":"Interact","x-mockingbird":{"parity":{"enabled":false,"reason":"Interactive OAuth transactions are exercised by protocol and independent JOSE tests."}},"responses":{"200":{"description":"200","content":{"text/html":{"schema":{"type":"string"}}}},"302":{"description":"302","content":{"text/html":{"schema":{"type":"string"}}}},"400":{"description":"400","content":{"text/html":{"schema":{"type":"string"}}}},"401":{"description":"401","content":{"text/html":{"schema":{"type":"string"}}}},"403":{"description":"403","content":{"text/html":{"schema":{"type":"string"}}}},"404":{"description":"404","content":{"text/html":{"schema":{"type":"string"}}}},"503":{"description":"503","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/token":{"post":{"operationId":"Token","summary":"Token","x-mockingbird":{"parity":{"enabled":false,"reason":"Interactive OAuth transactions are exercised by protocol and independent JOSE tests."}},"responses":{"200":{"description":"200","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"302":{"description":"302","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"400","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"description":"401","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"403":{"description":"403","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"404","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"503":{"description":"503","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/userinfo":{"get":{"operationId":"UserInfo","summary":"UserInfo","x-mockingbird":{"parity":{"enabled":false,"reason":"Interactive OAuth transactions are exercised by protocol and independent JOSE tests."}},"responses":{"200":{"description":"200","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"302":{"description":"302","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"400","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"description":"401","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"403":{"description":"403","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"404","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"503":{"description":"503","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}},"post":{"operationId":"UserInfoPost","summary":"UserInfo","x-mockingbird":{"parity":{"enabled":false,"reason":"Interactive OAuth transactions are exercised by protocol and independent JOSE tests."}},"responses":{"200":{"description":"200","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"302":{"description":"302","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"400","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"description":"401","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"403":{"description":"403","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"404","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"503":{"description":"503","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/revoke":{"post":{"operationId":"Revoke","summary":"Revoke","x-mockingbird":{"parity":{"enabled":false,"reason":"Interactive OAuth transactions are exercised by protocol and independent JOSE tests."}},"responses":{"200":{"description":"200","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"302":{"description":"302","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"400","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"description":"401","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"403":{"description":"403","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"404","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"503":{"description":"503","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/o/oauth2/v2/auth":{"get":{"operationId":"GoogleAuthorize","summary":"Authorize","x-mockingbird":{"parity":{"enabled":false,"reason":"Interactive OAuth transactions are exercised by protocol and independent JOSE tests."}},"responses":{"200":{"description":"200","content":{"text/html":{"schema":{"type":"string"}}}},"302":{"description":"302","content":{"text/html":{"schema":{"type":"string"}}}},"400":{"description":"400","content":{"text/html":{"schema":{"type":"string"}}}},"401":{"description":"401","content":{"text/html":{"schema":{"type":"string"}}}},"403":{"description":"403","content":{"text/html":{"schema":{"type":"string"}}}},"404":{"description":"404","content":{"text/html":{"schema":{"type":"string"}}}},"503":{"description":"503","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/o/oauth2/auth":{"get":{"operationId":"GoogleLegacyAuthorize","summary":"Authorize","x-mockingbird":{"parity":{"enabled":false,"reason":"Interactive OAuth transactions are exercised by protocol and independent JOSE tests."}},"responses":{"200":{"description":"200","content":{"text/html":{"schema":{"type":"string"}}}},"302":{"description":"302","content":{"text/html":{"schema":{"type":"string"}}}},"400":{"description":"400","content":{"text/html":{"schema":{"type":"string"}}}},"401":{"description":"401","content":{"text/html":{"schema":{"type":"string"}}}},"403":{"description":"403","content":{"text/html":{"schema":{"type":"string"}}}},"404":{"description":"404","content":{"text/html":{"schema":{"type":"string"}}}},"503":{"description":"503","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/auth/authorize":{"get":{"operationId":"AppleAuthorize","summary":"Authorize","x-mockingbird":{"parity":{"enabled":false,"reason":"Interactive OAuth transactions are exercised by protocol and independent JOSE tests."}},"responses":{"200":{"description":"200","content":{"text/html":{"schema":{"type":"string"}}}},"302":{"description":"302","content":{"text/html":{"schema":{"type":"string"}}}},"400":{"description":"400","content":{"text/html":{"schema":{"type":"string"}}}},"401":{"description":"401","content":{"text/html":{"schema":{"type":"string"}}}},"403":{"description":"403","content":{"text/html":{"schema":{"type":"string"}}}},"404":{"description":"404","content":{"text/html":{"schema":{"type":"string"}}}},"503":{"description":"503","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/auth/token":{"post":{"operationId":"AppleToken","summary":"Token","x-mockingbird":{"parity":{"enabled":false,"reason":"Interactive OAuth transactions are exercised by protocol and independent JOSE tests."}},"responses":{"200":{"description":"200","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"302":{"description":"302","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"400","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"description":"401","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"403":{"description":"403","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"404","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"503":{"description":"503","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/auth/keys":{"get":{"operationId":"AppleKeys","summary":"Jwks","x-mockingbird":{"parity":{"enabled":true,"reason":"Apple's public signing-key contract is checked by scripts/parity.ts."}},"responses":{"200":{"description":"200","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"302":{"description":"302","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"400","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"description":"401","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"403":{"description":"403","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"404","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"503":{"description":"503","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/oauth2/v3/certs":{"get":{"operationId":"GoogleKeys","summary":"Jwks","x-mockingbird":{"parity":{"enabled":true,"reason":"Google's public signing-key contract is checked by scripts/parity.ts."}},"responses":{"200":{"description":"200","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"302":{"description":"302","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"400","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"description":"401","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"403":{"description":"403","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"404","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"503":{"description":"503","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/v1/userinfo":{"get":{"operationId":"GoogleUserInfo","summary":"UserInfo","x-mockingbird":{"parity":{"enabled":false,"reason":"Interactive OAuth transactions are exercised by protocol and independent JOSE tests."}},"responses":{"200":{"description":"200","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"302":{"description":"302","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"400","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"description":"401","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"403":{"description":"403","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"404","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"503":{"description":"503","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}},"post":{"operationId":"GoogleUserInfoPost","summary":"UserInfo","x-mockingbird":{"parity":{"enabled":false,"reason":"Interactive OAuth transactions are exercised by protocol and independent JOSE tests."}},"responses":{"200":{"description":"200","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"302":{"description":"302","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"400","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"description":"401","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"403":{"description":"403","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"404","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"503":{"description":"503","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/oauth2/v3/userinfo":{"get":{"operationId":"GoogleV3UserInfo","summary":"UserInfo","x-mockingbird":{"parity":{"enabled":false,"reason":"Interactive OAuth transactions are exercised by protocol and independent JOSE tests."}},"responses":{"200":{"description":"200","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"302":{"description":"302","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"400","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"description":"401","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"403":{"description":"403","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"404","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"503":{"description":"503","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}},"post":{"operationId":"GoogleV3UserInfoPost","summary":"UserInfo","x-mockingbird":{"parity":{"enabled":false,"reason":"Interactive OAuth transactions are exercised by protocol and independent JOSE tests."}},"responses":{"200":{"description":"200","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"302":{"description":"302","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"400","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"description":"401","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"403":{"description":"403","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"404","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"503":{"description":"503","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/auth/revoke":{"post":{"operationId":"AppleRevoke","summary":"Revoke","x-mockingbird":{"parity":{"enabled":false,"reason":"Interactive OAuth transactions are exercised by protocol and independent JOSE tests."}},"responses":{"200":{"description":"200","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"302":{"description":"302","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"400","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"description":"401","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"403":{"description":"403","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"404","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"503":{"description":"503","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/oauth2/v2.0/authorize":{"get":{"operationId":"MicrosoftAuthorize","summary":"Authorize","x-mockingbird":{"parity":{"enabled":false,"reason":"Interactive OAuth transactions are exercised by protocol and independent JOSE tests."}},"responses":{"200":{"description":"200","content":{"text/html":{"schema":{"type":"string"}}}},"302":{"description":"302","content":{"text/html":{"schema":{"type":"string"}}}},"400":{"description":"400","content":{"text/html":{"schema":{"type":"string"}}}},"401":{"description":"401","content":{"text/html":{"schema":{"type":"string"}}}},"403":{"description":"403","content":{"text/html":{"schema":{"type":"string"}}}},"404":{"description":"404","content":{"text/html":{"schema":{"type":"string"}}}},"503":{"description":"503","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/oauth2/v2.0/token":{"post":{"operationId":"MicrosoftToken","summary":"Token","x-mockingbird":{"parity":{"enabled":false,"reason":"Interactive OAuth transactions are exercised by protocol and independent JOSE tests."}},"responses":{"200":{"description":"200","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"302":{"description":"302","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"400","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"description":"401","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"403":{"description":"403","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"404","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"503":{"description":"503","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/discovery/v2.0/keys":{"get":{"operationId":"MicrosoftKeys","summary":"Jwks","x-mockingbird":{"parity":{"enabled":true,"reason":"Microsoft's public signing-key contract is checked by scripts/parity.ts."}},"responses":{"200":{"description":"200","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"302":{"description":"302","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"400","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"description":"401","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"403":{"description":"403","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"404","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"503":{"description":"503","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/oidc/userinfo":{"get":{"operationId":"MicrosoftUserInfo","summary":"UserInfo","x-mockingbird":{"parity":{"enabled":false,"reason":"Interactive OAuth transactions are exercised by protocol and independent JOSE tests."}},"responses":{"200":{"description":"200","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"302":{"description":"302","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"400","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"description":"401","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"403":{"description":"403","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"404","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"503":{"description":"503","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}},"post":{"operationId":"MicrosoftUserInfoPost","summary":"UserInfo","x-mockingbird":{"parity":{"enabled":false,"reason":"Interactive OAuth transactions are exercised by protocol and independent JOSE tests."}},"responses":{"200":{"description":"200","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"302":{"description":"302","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"400","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"description":"401","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"403":{"description":"403","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"404","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"503":{"description":"503","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/login/oauth/authorize":{"get":{"operationId":"GitHubAuthorize","summary":"Authorize","x-mockingbird":{"parity":{"enabled":false,"reason":"Interactive OAuth transactions are exercised by protocol and independent JOSE tests."}},"responses":{"200":{"description":"200","content":{"text/html":{"schema":{"type":"string"}}}},"302":{"description":"302","content":{"text/html":{"schema":{"type":"string"}}}},"400":{"description":"400","content":{"text/html":{"schema":{"type":"string"}}}},"401":{"description":"401","content":{"text/html":{"schema":{"type":"string"}}}},"403":{"description":"403","content":{"text/html":{"schema":{"type":"string"}}}},"404":{"description":"404","content":{"text/html":{"schema":{"type":"string"}}}},"503":{"description":"503","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/login/oauth/access_token":{"post":{"operationId":"GitHubToken","summary":"Token","x-mockingbird":{"parity":{"enabled":false,"reason":"Interactive OAuth transactions are exercised by protocol and independent JOSE tests."}},"responses":{"200":{"description":"200","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}},"application/x-www-form-urlencoded":{"schema":{"type":"string"}}}},"302":{"description":"302","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}},"application/x-www-form-urlencoded":{"schema":{"type":"string"}}}},"400":{"description":"400","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}},"application/x-www-form-urlencoded":{"schema":{"type":"string"}}}},"401":{"description":"401","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}},"application/x-www-form-urlencoded":{"schema":{"type":"string"}}}},"403":{"description":"403","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}},"application/x-www-form-urlencoded":{"schema":{"type":"string"}}}},"404":{"description":"404","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}},"application/x-www-form-urlencoded":{"schema":{"type":"string"}}}},"503":{"description":"503","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}},"application/x-www-form-urlencoded":{"schema":{"type":"string"}}}}}}},"/user":{"get":{"operationId":"GitHubUser","summary":"UserInfo","x-mockingbird":{"parity":{"enabled":false,"reason":"Interactive OAuth transactions are exercised by protocol and independent JOSE tests."}},"responses":{"200":{"description":"200","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"302":{"description":"302","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"400","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"description":"401","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"403":{"description":"403","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"404","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"503":{"description":"503","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}},"post":{"operationId":"GitHubUserPost","summary":"UserInfo","x-mockingbird":{"parity":{"enabled":false,"reason":"Interactive OAuth transactions are exercised by protocol and independent JOSE tests."}},"responses":{"200":{"description":"200","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"302":{"description":"302","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"400","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"description":"401","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"403":{"description":"403","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"404","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"503":{"description":"503","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/user/emails":{"get":{"operationId":"GitHubEmails","summary":"UserInfo","x-mockingbird":{"parity":{"enabled":false,"reason":"Interactive OAuth transactions are exercised by protocol and independent JOSE tests."}},"responses":{"200":{"description":"200","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","additionalProperties":true}}}}},"302":{"description":"302","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"400","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"description":"401","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"403":{"description":"403","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"404","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"503":{"description":"503","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}},"post":{"operationId":"GitHubEmailsPost","summary":"UserInfo","x-mockingbird":{"parity":{"enabled":false,"reason":"Interactive OAuth transactions are exercised by protocol and independent JOSE tests."}},"responses":{"200":{"description":"200","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","additionalProperties":true}}}}},"302":{"description":"302","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"400","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"description":"401","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"403":{"description":"403","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"404","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"503":{"description":"503","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/":{"get":{"operationId":"Welcome","summary":"InteractionPage","x-mockingbird":{"parity":{"enabled":false,"reason":"Interactive OAuth transactions are exercised by protocol and independent JOSE tests."}},"responses":{"200":{"description":"200","content":{"text/html":{"schema":{"type":"string"}}}},"302":{"description":"302","content":{"text/html":{"schema":{"type":"string"}}}},"400":{"description":"400","content":{"text/html":{"schema":{"type":"string"}}}},"401":{"description":"401","content":{"text/html":{"schema":{"type":"string"}}}},"403":{"description":"403","content":{"text/html":{"schema":{"type":"string"}}}},"404":{"description":"404","content":{"text/html":{"schema":{"type":"string"}}}},"503":{"description":"503","content":{"text/html":{"schema":{"type":"string"}}}}}}}}}`);
2378
+ var document = JSON.parse(`{"openapi":"3.1.0","info":{"title":"Mockingbird OAuth & Social Login","version":"1.0.0"},"paths":{"/.well-known/openid-configuration":{"get":{"operationId":"Discovery","summary":"Discovery","x-mockingbird":{"parity":{"enabled":true,"reason":"Google, Apple and Microsoft discovery metadata is checked against their public live endpoints by scripts/parity.ts."}},"responses":{"200":{"description":"200","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"302":{"description":"302","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"400","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"description":"401","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"403":{"description":"403","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"404","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"503":{"description":"503","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/jwks":{"get":{"operationId":"Jwks","summary":"Jwks","x-mockingbird":{"parity":{"enabled":false,"reason":"Interactive OAuth transactions are exercised by protocol and independent JOSE tests."}},"responses":{"200":{"description":"200","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"302":{"description":"302","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"400","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"description":"401","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"403":{"description":"403","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"404","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"503":{"description":"503","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/authorize":{"get":{"operationId":"Authorize","summary":"Authorize","x-mockingbird":{"parity":{"enabled":false,"reason":"Interactive OAuth transactions are exercised by protocol and independent JOSE tests."}},"responses":{"200":{"description":"200","content":{"text/html":{"schema":{"type":"string"}}}},"302":{"description":"302","content":{"text/html":{"schema":{"type":"string"}}}},"400":{"description":"400","content":{"text/html":{"schema":{"type":"string"}}}},"401":{"description":"401","content":{"text/html":{"schema":{"type":"string"}}}},"403":{"description":"403","content":{"text/html":{"schema":{"type":"string"}}}},"404":{"description":"404","content":{"text/html":{"schema":{"type":"string"}}}},"503":{"description":"503","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/interaction":{"get":{"operationId":"InteractionPage","summary":"InteractionPage","x-mockingbird":{"parity":{"enabled":false,"reason":"Interactive OAuth transactions are exercised by protocol and independent JOSE tests. The pages carry the documented oauth-mock-* data-testid hooks (README, \\"Test hooks on the interaction pages\\")."}},"responses":{"200":{"description":"200","content":{"text/html":{"schema":{"type":"string"}}}},"302":{"description":"302","content":{"text/html":{"schema":{"type":"string"}}}},"400":{"description":"400","content":{"text/html":{"schema":{"type":"string"}}}},"401":{"description":"401","content":{"text/html":{"schema":{"type":"string"}}}},"403":{"description":"403","content":{"text/html":{"schema":{"type":"string"}}}},"404":{"description":"404","content":{"text/html":{"schema":{"type":"string"}}}},"503":{"description":"503","content":{"text/html":{"schema":{"type":"string"}}}}}},"post":{"operationId":"Interact","summary":"Interact","x-mockingbird":{"parity":{"enabled":false,"reason":"Interactive OAuth transactions are exercised by protocol and independent JOSE tests. The pages carry the documented oauth-mock-* data-testid hooks (README, \\"Test hooks on the interaction pages\\")."}},"responses":{"200":{"description":"200","content":{"text/html":{"schema":{"type":"string"}}}},"302":{"description":"302","content":{"text/html":{"schema":{"type":"string"}}}},"400":{"description":"400","content":{"text/html":{"schema":{"type":"string"}}}},"401":{"description":"401","content":{"text/html":{"schema":{"type":"string"}}}},"403":{"description":"403","content":{"text/html":{"schema":{"type":"string"}}}},"404":{"description":"404","content":{"text/html":{"schema":{"type":"string"}}}},"503":{"description":"503","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/token":{"post":{"operationId":"Token","summary":"Token","x-mockingbird":{"parity":{"enabled":false,"reason":"Interactive OAuth transactions are exercised by protocol and independent JOSE tests."}},"responses":{"200":{"description":"200","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"302":{"description":"302","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"400","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"description":"401","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"403":{"description":"403","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"404","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"503":{"description":"503","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/userinfo":{"get":{"operationId":"UserInfo","summary":"UserInfo","x-mockingbird":{"parity":{"enabled":false,"reason":"Interactive OAuth transactions are exercised by protocol and independent JOSE tests."}},"responses":{"200":{"description":"200","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"302":{"description":"302","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"400","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"description":"401","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"403":{"description":"403","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"404","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"503":{"description":"503","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}},"post":{"operationId":"UserInfoPost","summary":"UserInfo","x-mockingbird":{"parity":{"enabled":false,"reason":"Interactive OAuth transactions are exercised by protocol and independent JOSE tests."}},"responses":{"200":{"description":"200","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"302":{"description":"302","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"400","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"description":"401","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"403":{"description":"403","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"404","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"503":{"description":"503","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/revoke":{"post":{"operationId":"Revoke","summary":"Revoke","x-mockingbird":{"parity":{"enabled":false,"reason":"Interactive OAuth transactions are exercised by protocol and independent JOSE tests."}},"responses":{"200":{"description":"200","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"302":{"description":"302","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"400","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"description":"401","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"403":{"description":"403","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"404","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"503":{"description":"503","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/o/oauth2/v2/auth":{"get":{"operationId":"GoogleAuthorize","summary":"Authorize","x-mockingbird":{"parity":{"enabled":false,"reason":"Interactive OAuth transactions are exercised by protocol and independent JOSE tests."}},"responses":{"200":{"description":"200","content":{"text/html":{"schema":{"type":"string"}}}},"302":{"description":"302","content":{"text/html":{"schema":{"type":"string"}}}},"400":{"description":"400","content":{"text/html":{"schema":{"type":"string"}}}},"401":{"description":"401","content":{"text/html":{"schema":{"type":"string"}}}},"403":{"description":"403","content":{"text/html":{"schema":{"type":"string"}}}},"404":{"description":"404","content":{"text/html":{"schema":{"type":"string"}}}},"503":{"description":"503","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/o/oauth2/auth":{"get":{"operationId":"GoogleLegacyAuthorize","summary":"Authorize","x-mockingbird":{"parity":{"enabled":false,"reason":"Interactive OAuth transactions are exercised by protocol and independent JOSE tests."}},"responses":{"200":{"description":"200","content":{"text/html":{"schema":{"type":"string"}}}},"302":{"description":"302","content":{"text/html":{"schema":{"type":"string"}}}},"400":{"description":"400","content":{"text/html":{"schema":{"type":"string"}}}},"401":{"description":"401","content":{"text/html":{"schema":{"type":"string"}}}},"403":{"description":"403","content":{"text/html":{"schema":{"type":"string"}}}},"404":{"description":"404","content":{"text/html":{"schema":{"type":"string"}}}},"503":{"description":"503","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/auth/authorize":{"get":{"operationId":"AppleAuthorize","summary":"Authorize","x-mockingbird":{"parity":{"enabled":false,"reason":"Interactive OAuth transactions are exercised by protocol and independent JOSE tests."}},"responses":{"200":{"description":"200","content":{"text/html":{"schema":{"type":"string"}}}},"302":{"description":"302","content":{"text/html":{"schema":{"type":"string"}}}},"400":{"description":"400","content":{"text/html":{"schema":{"type":"string"}}}},"401":{"description":"401","content":{"text/html":{"schema":{"type":"string"}}}},"403":{"description":"403","content":{"text/html":{"schema":{"type":"string"}}}},"404":{"description":"404","content":{"text/html":{"schema":{"type":"string"}}}},"503":{"description":"503","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/auth/token":{"post":{"operationId":"AppleToken","summary":"Token","x-mockingbird":{"parity":{"enabled":false,"reason":"Interactive OAuth transactions are exercised by protocol and independent JOSE tests."}},"responses":{"200":{"description":"200","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"302":{"description":"302","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"400","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"description":"401","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"403":{"description":"403","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"404","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"503":{"description":"503","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/auth/keys":{"get":{"operationId":"AppleKeys","summary":"Jwks","x-mockingbird":{"parity":{"enabled":true,"reason":"Apple's public signing-key contract is checked by scripts/parity.ts."}},"responses":{"200":{"description":"200","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"302":{"description":"302","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"400","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"description":"401","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"403":{"description":"403","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"404","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"503":{"description":"503","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/oauth2/v3/certs":{"get":{"operationId":"GoogleKeys","summary":"Jwks","x-mockingbird":{"parity":{"enabled":true,"reason":"Google's public signing-key contract is checked by scripts/parity.ts."}},"responses":{"200":{"description":"200","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"302":{"description":"302","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"400","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"description":"401","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"403":{"description":"403","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"404","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"503":{"description":"503","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/v1/userinfo":{"get":{"operationId":"GoogleUserInfo","summary":"UserInfo","x-mockingbird":{"parity":{"enabled":false,"reason":"Interactive OAuth transactions are exercised by protocol and independent JOSE tests."}},"responses":{"200":{"description":"200","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"302":{"description":"302","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"400","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"description":"401","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"403":{"description":"403","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"404","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"503":{"description":"503","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}},"post":{"operationId":"GoogleUserInfoPost","summary":"UserInfo","x-mockingbird":{"parity":{"enabled":false,"reason":"Interactive OAuth transactions are exercised by protocol and independent JOSE tests."}},"responses":{"200":{"description":"200","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"302":{"description":"302","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"400","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"description":"401","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"403":{"description":"403","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"404","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"503":{"description":"503","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/oauth2/v3/userinfo":{"get":{"operationId":"GoogleV3UserInfo","summary":"UserInfo","x-mockingbird":{"parity":{"enabled":false,"reason":"Interactive OAuth transactions are exercised by protocol and independent JOSE tests."}},"responses":{"200":{"description":"200","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"302":{"description":"302","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"400","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"description":"401","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"403":{"description":"403","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"404","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"503":{"description":"503","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}},"post":{"operationId":"GoogleV3UserInfoPost","summary":"UserInfo","x-mockingbird":{"parity":{"enabled":false,"reason":"Interactive OAuth transactions are exercised by protocol and independent JOSE tests."}},"responses":{"200":{"description":"200","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"302":{"description":"302","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"400","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"description":"401","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"403":{"description":"403","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"404","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"503":{"description":"503","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/auth/revoke":{"post":{"operationId":"AppleRevoke","summary":"Revoke","x-mockingbird":{"parity":{"enabled":false,"reason":"Interactive OAuth transactions are exercised by protocol and independent JOSE tests."}},"responses":{"200":{"description":"200","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"302":{"description":"302","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"400","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"description":"401","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"403":{"description":"403","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"404","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"503":{"description":"503","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/oauth2/v2.0/authorize":{"get":{"operationId":"MicrosoftAuthorize","summary":"Authorize","x-mockingbird":{"parity":{"enabled":false,"reason":"Interactive OAuth transactions are exercised by protocol and independent JOSE tests."}},"responses":{"200":{"description":"200","content":{"text/html":{"schema":{"type":"string"}}}},"302":{"description":"302","content":{"text/html":{"schema":{"type":"string"}}}},"400":{"description":"400","content":{"text/html":{"schema":{"type":"string"}}}},"401":{"description":"401","content":{"text/html":{"schema":{"type":"string"}}}},"403":{"description":"403","content":{"text/html":{"schema":{"type":"string"}}}},"404":{"description":"404","content":{"text/html":{"schema":{"type":"string"}}}},"503":{"description":"503","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/oauth2/v2.0/token":{"post":{"operationId":"MicrosoftToken","summary":"Token","x-mockingbird":{"parity":{"enabled":false,"reason":"Interactive OAuth transactions are exercised by protocol and independent JOSE tests."}},"responses":{"200":{"description":"200","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"302":{"description":"302","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"400","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"description":"401","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"403":{"description":"403","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"404","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"503":{"description":"503","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/discovery/v2.0/keys":{"get":{"operationId":"MicrosoftKeys","summary":"Jwks","x-mockingbird":{"parity":{"enabled":true,"reason":"Microsoft's public signing-key contract is checked by scripts/parity.ts."}},"responses":{"200":{"description":"200","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"302":{"description":"302","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"400","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"description":"401","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"403":{"description":"403","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"404","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"503":{"description":"503","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/oidc/userinfo":{"get":{"operationId":"MicrosoftUserInfo","summary":"UserInfo","x-mockingbird":{"parity":{"enabled":false,"reason":"Interactive OAuth transactions are exercised by protocol and independent JOSE tests."}},"responses":{"200":{"description":"200","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"302":{"description":"302","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"400","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"description":"401","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"403":{"description":"403","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"404","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"503":{"description":"503","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}},"post":{"operationId":"MicrosoftUserInfoPost","summary":"UserInfo","x-mockingbird":{"parity":{"enabled":false,"reason":"Interactive OAuth transactions are exercised by protocol and independent JOSE tests."}},"responses":{"200":{"description":"200","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"302":{"description":"302","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"400","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"description":"401","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"403":{"description":"403","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"404","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"503":{"description":"503","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/login/oauth/authorize":{"get":{"operationId":"GitHubAuthorize","summary":"Authorize","x-mockingbird":{"parity":{"enabled":false,"reason":"Interactive OAuth transactions are exercised by protocol and independent JOSE tests."}},"responses":{"200":{"description":"200","content":{"text/html":{"schema":{"type":"string"}}}},"302":{"description":"302","content":{"text/html":{"schema":{"type":"string"}}}},"400":{"description":"400","content":{"text/html":{"schema":{"type":"string"}}}},"401":{"description":"401","content":{"text/html":{"schema":{"type":"string"}}}},"403":{"description":"403","content":{"text/html":{"schema":{"type":"string"}}}},"404":{"description":"404","content":{"text/html":{"schema":{"type":"string"}}}},"503":{"description":"503","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/login/oauth/access_token":{"post":{"operationId":"GitHubToken","summary":"Token","x-mockingbird":{"parity":{"enabled":false,"reason":"Interactive OAuth transactions are exercised by protocol and independent JOSE tests."}},"responses":{"200":{"description":"200","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}},"application/x-www-form-urlencoded":{"schema":{"type":"string"}}}},"302":{"description":"302","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}},"application/x-www-form-urlencoded":{"schema":{"type":"string"}}}},"400":{"description":"400","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}},"application/x-www-form-urlencoded":{"schema":{"type":"string"}}}},"401":{"description":"401","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}},"application/x-www-form-urlencoded":{"schema":{"type":"string"}}}},"403":{"description":"403","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}},"application/x-www-form-urlencoded":{"schema":{"type":"string"}}}},"404":{"description":"404","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}},"application/x-www-form-urlencoded":{"schema":{"type":"string"}}}},"503":{"description":"503","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}},"application/x-www-form-urlencoded":{"schema":{"type":"string"}}}}}}},"/user":{"get":{"operationId":"GitHubUser","summary":"UserInfo","x-mockingbird":{"parity":{"enabled":false,"reason":"Interactive OAuth transactions are exercised by protocol and independent JOSE tests."}},"responses":{"200":{"description":"200","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"302":{"description":"302","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"400","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"description":"401","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"403":{"description":"403","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"404","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"503":{"description":"503","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}},"post":{"operationId":"GitHubUserPost","summary":"UserInfo","x-mockingbird":{"parity":{"enabled":false,"reason":"Interactive OAuth transactions are exercised by protocol and independent JOSE tests."}},"responses":{"200":{"description":"200","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"302":{"description":"302","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"400","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"description":"401","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"403":{"description":"403","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"404","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"503":{"description":"503","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/user/emails":{"get":{"operationId":"GitHubEmails","summary":"UserInfo","x-mockingbird":{"parity":{"enabled":false,"reason":"Interactive OAuth transactions are exercised by protocol and independent JOSE tests."}},"responses":{"200":{"description":"200","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","additionalProperties":true}}}}},"302":{"description":"302","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"400","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"description":"401","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"403":{"description":"403","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"404","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"503":{"description":"503","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}},"post":{"operationId":"GitHubEmailsPost","summary":"UserInfo","x-mockingbird":{"parity":{"enabled":false,"reason":"Interactive OAuth transactions are exercised by protocol and independent JOSE tests."}},"responses":{"200":{"description":"200","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","additionalProperties":true}}}}},"302":{"description":"302","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"400","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"description":"401","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"403":{"description":"403","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"404","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"503":{"description":"503","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/":{"get":{"operationId":"Welcome","summary":"InteractionPage","x-mockingbird":{"parity":{"enabled":false,"reason":"Interactive OAuth transactions are exercised by protocol and independent JOSE tests."}},"responses":{"200":{"description":"200","content":{"text/html":{"schema":{"type":"string"}}}},"302":{"description":"302","content":{"text/html":{"schema":{"type":"string"}}}},"400":{"description":"400","content":{"text/html":{"schema":{"type":"string"}}}},"401":{"description":"401","content":{"text/html":{"schema":{"type":"string"}}}},"403":{"description":"403","content":{"text/html":{"schema":{"type":"string"}}}},"404":{"description":"404","content":{"text/html":{"schema":{"type":"string"}}}},"503":{"description":"503","content":{"text/html":{"schema":{"type":"string"}}}}}}}}}`);
2375
2379
  var operationIds = ["Discovery", "Jwks", "Authorize", "InteractionPage", "Interact", "Token", "UserInfo", "UserInfoPost", "Revoke", "GoogleAuthorize", "GoogleLegacyAuthorize", "AppleAuthorize", "AppleToken", "AppleKeys", "GoogleKeys", "GoogleUserInfo", "GoogleUserInfoPost", "GoogleV3UserInfo", "GoogleV3UserInfoPost", "AppleRevoke", "MicrosoftAuthorize", "MicrosoftToken", "MicrosoftKeys", "MicrosoftUserInfo", "MicrosoftUserInfoPost", "GitHubAuthorize", "GitHubToken", "GitHubUser", "GitHubUserPost", "GitHubEmails", "GitHubEmailsPost", "Welcome"];
2376
2380
  var supportedOperationIds = ["Discovery", "Jwks", "Authorize", "InteractionPage", "Interact", "Token", "UserInfo", "UserInfoPost", "Revoke", "GoogleAuthorize", "GoogleLegacyAuthorize", "AppleAuthorize", "AppleToken", "AppleKeys", "GoogleKeys", "GoogleUserInfo", "GoogleUserInfoPost", "GoogleV3UserInfo", "GoogleV3UserInfoPost", "AppleRevoke", "MicrosoftAuthorize", "MicrosoftToken", "MicrosoftKeys", "MicrosoftUserInfo", "MicrosoftUserInfoPost", "GitHubAuthorize", "GitHubToken", "GitHubUser", "GitHubUserPost", "GitHubEmails", "GitHubEmailsPost", "Welcome"];
2377
2381
 
@@ -3187,7 +3191,10 @@ var OAuthAPI = class {
3187
3191
  return page(
3188
3192
  "Session expired",
3189
3193
  '<span class="eyebrow">Let\u2019s try again</span><h1 id="title">This sign-in expired</h1><p>Return to your application and start sign-in again.</p>',
3190
- 400
3194
+ 400,
3195
+ void 0,
3196
+ void 0,
3197
+ "oauth-mock-error"
3191
3198
  );
3192
3199
  const accounts = () => this.accounts.list({ order: "oldest", where: (a) => !a.disabled }).map((a) => a.value);
3193
3200
  if (request.method === "GET")
@@ -3249,6 +3256,16 @@ var OAuthAPI = class {
3249
3256
  );
3250
3257
  auth.accountId = account.id;
3251
3258
  auth.authTime = this.now();
3259
+ const granted = this.consents.get(JSON.stringify([client.id, account.id]));
3260
+ if (this.provider === "google" && !auth.forceConsent && granted && [...scopes(auth.scope)].every((s) => scopes(granted.scope).has(s))) {
3261
+ this.transactions.delete(id);
3262
+ return this.startSession(
3263
+ await this.finish(auth, issuer),
3264
+ account.id,
3265
+ auth.authTime,
3266
+ issuer
3267
+ );
3268
+ }
3252
3269
  this.transactions.update(id, auth);
3253
3270
  return this.consent(id, client, account, auth, issuer);
3254
3271
  }
@@ -3261,21 +3278,24 @@ var OAuthAPI = class {
3261
3278
  if (choice && this.provider === "apple" && (this.behavior.config.apple?.emailMode ?? "choose") === "choose" && !this.identities.has(this.identityKey(client, account.id)))
3262
3279
  auth.emailChoice = choice;
3263
3280
  this.transactions.delete(id);
3264
- const result = await this.finish(auth, issuer);
3265
- const session = random();
3266
- this.sessions.insert(session, {
3267
- accountId: account.id,
3268
- authTime: auth.authTime,
3269
- expires: this.now() + 864e5
3270
- });
3271
- result.headers.append(
3272
- this.options.cookieHeaders?.response ?? "set-cookie",
3273
- `mb_session=${session}; Path=${new URL(issuer).pathname.replace(/\/$/, "") || "/"}; HttpOnly; SameSite=Lax; Max-Age=86400${issuer.startsWith("https:") ? "; Secure" : ""}`
3281
+ return this.startSession(
3282
+ await this.finish(auth, issuer),
3283
+ account.id,
3284
+ auth.authTime,
3285
+ issuer
3274
3286
  );
3275
- return result;
3276
3287
  }
3277
3288
  return fail("invalid_request", "Invalid interaction action");
3278
3289
  }
3290
+ startSession(result, accountId, authTime, issuer) {
3291
+ const session = random();
3292
+ this.sessions.insert(session, { accountId, authTime, expires: this.now() + 864e5 });
3293
+ result.headers.append(
3294
+ this.options.cookieHeaders?.response ?? "set-cookie",
3295
+ `mb_session=${session}; Path=${new URL(issuer).pathname.replace(/\/$/, "") || "/"}; HttpOnly; SameSite=Lax; Max-Age=86400${issuer.startsWith("https:") ? "; Secure" : ""}`
3296
+ );
3297
+ return result;
3298
+ }
3279
3299
  async finish(auth, issuer) {
3280
3300
  const behavior = this.behavior.config;
3281
3301
  if (auth.decisions.denyConsent || behavior.consent?.error)
@@ -3348,10 +3368,11 @@ var OAuthAPI = class {
3348
3368
  values
3349
3369
  ).map(([k, v]) => `<input type="hidden" name="${escapeHtml(k)}" value="${escapeHtml(v)}">`).join(
3350
3370
  ""
3351
- )}<button class="primary">Continue</button></form><script nonce="${nonce}">document.getElementById('callback').submit()</script>`,
3371
+ )}<button class="primary" data-testid="oauth-mock-form-post-continue">Continue</button></form><script nonce="${nonce}">document.getElementById('callback').submit()</script>`,
3352
3372
  200,
3353
3373
  formTarget(auth.redirectUri),
3354
- nonce
3374
+ nonce,
3375
+ "oauth-mock-form-post"
3355
3376
  );
3356
3377
  return result;
3357
3378
  }
@@ -3574,4 +3595,4 @@ export {
3574
3595
  createMultiRuntime,
3575
3596
  OAuthAPI
3576
3597
  };
3577
- //# sourceMappingURL=chunk-I24F66FL.js.map
3598
+ //# sourceMappingURL=chunk-JA62N2QU.js.map