@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/CHANGELOG.md +22 -1
- package/README.md +51 -6
- package/dist/{chunk-X5QMVVR5.js → chunk-U4WWQUOX.js} +2 -2
- package/dist/{chunk-I24F66FL.js → chunk-XUUSJ73W.js} +197 -36
- package/dist/chunk-XUUSJ73W.js.map +7 -0
- package/dist/cli.js +2 -2
- package/dist/index.d.ts +60 -4
- package/dist/index.js +1 -1
- package/dist/server.d.ts +60 -4
- package/dist/server.js +2 -2
- package/package.json +1 -1
- package/dist/chunk-I24F66FL.js.map +0 -7
- /package/dist/{chunk-X5QMVVR5.js.map → chunk-U4WWQUOX.js.map} +0 -0
|
@@ -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
|
|
1387
|
+
var PACKAGE_VERSION = true ? "1.2.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" } });
|
|
@@ -2069,7 +2069,10 @@ var OAUTH_SCENARIOS = {
|
|
|
2069
2069
|
rotating_refresh_tokens: { tokens: { refreshRotation: "rotate" } },
|
|
2070
2070
|
short_lived_tokens: { tokens: { accessTtlSeconds: 5, codeTtlSeconds: 5, refreshTtlSeconds: 30 } },
|
|
2071
2071
|
consent_denied: { consent: { error: "access_denied" } },
|
|
2072
|
-
intermittent_token_failure: { probabilities: { tokenUnavailable: 0.25 } }
|
|
2072
|
+
intermittent_token_failure: { probabilities: { tokenUnavailable: 0.25 } },
|
|
2073
|
+
id_token_clock_ahead: { tokens: { idTokenClockSkewSeconds: 600 } },
|
|
2074
|
+
id_token_stale: { tokens: { idTokenClockSkewSeconds: -7200 } },
|
|
2075
|
+
id_token_unknown_key: { tokens: { idTokenSigningKey: "unpublished" } }
|
|
2073
2076
|
};
|
|
2074
2077
|
var object = (v) => v !== null && typeof v === "object" && !Array.isArray(v);
|
|
2075
2078
|
var keys = (value, allowed) => {
|
|
@@ -2154,10 +2157,16 @@ function validateBehavior(input) {
|
|
|
2154
2157
|
"codeTtlSeconds",
|
|
2155
2158
|
"refreshTtlSeconds",
|
|
2156
2159
|
"refreshRotation",
|
|
2157
|
-
"refreshError"
|
|
2160
|
+
"refreshError",
|
|
2161
|
+
"idTokenClockSkewSeconds",
|
|
2162
|
+
"idTokenSigningKey"
|
|
2158
2163
|
]);
|
|
2159
2164
|
enumeration(tokens.refreshRotation, ["reuse", "rotate"]);
|
|
2160
2165
|
enumeration(tokens.refreshError, ["invalid_grant", "invalid_rapt"]);
|
|
2166
|
+
enumeration(tokens.idTokenSigningKey, ["published", "unpublished"]);
|
|
2167
|
+
const skew = tokens.idTokenClockSkewSeconds;
|
|
2168
|
+
if (skew !== void 0 && (typeof skew !== "number" || !Number.isSafeInteger(skew) || Math.abs(skew) > 31536e4))
|
|
2169
|
+
throw new Error("idTokenClockSkewSeconds must be an integer in [-315360000,315360000]");
|
|
2161
2170
|
for (const key of ["accessTtlSeconds", "codeTtlSeconds", "refreshTtlSeconds"]) {
|
|
2162
2171
|
const v = tokens[key];
|
|
2163
2172
|
if (v !== void 0 && (typeof v !== "number" || !Number.isSafeInteger(v) || v < 1 || v > 31536e4))
|
|
@@ -2322,9 +2331,9 @@ var style = `
|
|
|
2322
2331
|
.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
2332
|
|
|
2324
2333
|
`;
|
|
2325
|
-
function page(title, body, status = 200, action = "'self'", nonce = crypto.randomUUID()) {
|
|
2334
|
+
function page(title, body, status = 200, action = "'self'", nonce = crypto.randomUUID(), testId = "") {
|
|
2326
2335
|
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>`,
|
|
2336
|
+
`<!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
2337
|
{
|
|
2329
2338
|
status,
|
|
2330
2339
|
headers: {
|
|
@@ -2340,13 +2349,15 @@ function page(title, body, status = 200, action = "'self'", nonce = crypto.rando
|
|
|
2340
2349
|
function loginPage(transaction, client, accounts, base, action, signup = false, error = "") {
|
|
2341
2350
|
const hidden = `<input type="hidden" name="transaction" value="${escapeHtml(transaction)}">`;
|
|
2342
2351
|
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 & 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>`;
|
|
2352
|
+
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>` : ""}`;
|
|
2353
|
+
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 & 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
2354
|
return page(
|
|
2346
2355
|
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>`,
|
|
2356
|
+
`${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
2357
|
error ? 400 : 200,
|
|
2349
|
-
action
|
|
2358
|
+
action,
|
|
2359
|
+
void 0,
|
|
2360
|
+
signup ? "oauth-mock-signup" : "oauth-mock-chooser"
|
|
2350
2361
|
);
|
|
2351
2362
|
}
|
|
2352
2363
|
function consentPage(transaction, client, account, scopes2, base, action, privacy) {
|
|
@@ -2357,21 +2368,23 @@ function consentPage(transaction, client, account, scopes2, base, action, privac
|
|
|
2357
2368
|
name: "View your name",
|
|
2358
2369
|
offline_access: "Stay connected when you\u2019re away"
|
|
2359
2370
|
};
|
|
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>` : "";
|
|
2371
|
+
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
2372
|
return page(
|
|
2362
2373
|
"Review access",
|
|
2363
2374
|
`<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
2375
|
(s) => `<li><span class="check" aria-hidden="true">\u2713</span>${escapeHtml(labels[s] ?? s)}</li>`
|
|
2365
2376
|
).join(
|
|
2366
2377
|
""
|
|
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 & continue</button><button class="secondary" name="action" value="deny">Cancel</button></form>`,
|
|
2378
|
+
)}</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 & continue</button><button class="secondary" data-testid="oauth-mock-deny" name="action" value="deny">Cancel</button></form>`,
|
|
2368
2379
|
200,
|
|
2369
|
-
action
|
|
2380
|
+
action,
|
|
2381
|
+
void 0,
|
|
2382
|
+
"oauth-mock-consent"
|
|
2370
2383
|
);
|
|
2371
2384
|
}
|
|
2372
2385
|
|
|
2373
2386
|
// 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"}}}}}}}}}`);
|
|
2387
|
+
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
2388
|
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
2389
|
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
2390
|
|
|
@@ -2420,12 +2433,44 @@ function createRuntime2(options = {}) {
|
|
|
2420
2433
|
return Response.json({ error: String(error) }, { status: 400 });
|
|
2421
2434
|
}
|
|
2422
2435
|
},
|
|
2423
|
-
"POST /consents/revoke": ({ namespace, body }) => {
|
|
2436
|
+
"POST /consents/revoke": async ({ namespace, body, request }) => {
|
|
2424
2437
|
const input = body;
|
|
2425
2438
|
if (!input || typeof input.clientId !== "string" || typeof input.accountId !== "string")
|
|
2426
2439
|
return Response.json({ error: "clientId and accountId are required" }, { status: 400 });
|
|
2427
|
-
runtime.instance(namespace)
|
|
2428
|
-
|
|
2440
|
+
const api = runtime.instance(namespace);
|
|
2441
|
+
const notifications = await api.revokeConsent(
|
|
2442
|
+
input.clientId,
|
|
2443
|
+
input.accountId,
|
|
2444
|
+
api.issuer(request)
|
|
2445
|
+
);
|
|
2446
|
+
return Response.json({ revoked: true, notifications });
|
|
2447
|
+
},
|
|
2448
|
+
"POST /accounts/delete": async ({ namespace, body, request }) => {
|
|
2449
|
+
const input = body;
|
|
2450
|
+
if (!input || typeof input.accountId !== "string")
|
|
2451
|
+
return Response.json({ error: "accountId is required" }, { status: 400 });
|
|
2452
|
+
const api = runtime.instance(namespace);
|
|
2453
|
+
if (!api.accounts.has(input.accountId))
|
|
2454
|
+
return Response.json({ error: "Unknown account" }, { status: 404 });
|
|
2455
|
+
const notifications = await api.deleteAccount(input.accountId, api.issuer(request));
|
|
2456
|
+
return Response.json({ deleted: true, notifications });
|
|
2457
|
+
},
|
|
2458
|
+
"POST /relay-forwarding": async ({ namespace, body, request }) => {
|
|
2459
|
+
const input = body;
|
|
2460
|
+
if (!input || typeof input.accountId !== "string" || typeof input.forwarding !== "boolean")
|
|
2461
|
+
return Response.json(
|
|
2462
|
+
{ error: "accountId and boolean forwarding are required" },
|
|
2463
|
+
{ status: 400 }
|
|
2464
|
+
);
|
|
2465
|
+
const api = runtime.instance(namespace);
|
|
2466
|
+
if (!api.accounts.has(input.accountId))
|
|
2467
|
+
return Response.json({ error: "Unknown account" }, { status: 404 });
|
|
2468
|
+
const notifications = await api.setRelayForwarding(
|
|
2469
|
+
input.accountId,
|
|
2470
|
+
input.forwarding,
|
|
2471
|
+
api.issuer(request)
|
|
2472
|
+
);
|
|
2473
|
+
return Response.json({ forwarding: input.forwarding, notifications });
|
|
2429
2474
|
},
|
|
2430
2475
|
"POST /keys/rotate": ({ namespace, body }) => {
|
|
2431
2476
|
const input = body;
|
|
@@ -2637,6 +2682,8 @@ var OAuthAPI = class {
|
|
|
2637
2682
|
consents;
|
|
2638
2683
|
signer = new Signer();
|
|
2639
2684
|
previousSigners = [];
|
|
2685
|
+
/** Never published: signs ID tokens for `tokens.idTokenSigningKey: "unpublished"`. */
|
|
2686
|
+
unpublishedSigner;
|
|
2640
2687
|
behavior;
|
|
2641
2688
|
identities;
|
|
2642
2689
|
appleDisclosures;
|
|
@@ -2680,6 +2727,10 @@ var OAuthAPI = class {
|
|
|
2680
2727
|
throw new Error(
|
|
2681
2728
|
"Apple client requires teamId, keyId and a public P-256 JWK, without a static secret"
|
|
2682
2729
|
);
|
|
2730
|
+
if (client.apple?.notificationUrl !== void 0 && !(typeof client.apple.notificationUrl === "string" && safeRedirect(client.apple.notificationUrl) && WEB_SCHEMES.has(new URL(client.apple.notificationUrl).protocol)))
|
|
2731
|
+
throw new Error(
|
|
2732
|
+
"apple.notificationUrl must be an HTTP(S) URL without fragment or credentials"
|
|
2733
|
+
);
|
|
2683
2734
|
this.clients.insert(client.id, structuredClone(client));
|
|
2684
2735
|
return client;
|
|
2685
2736
|
}
|
|
@@ -2700,7 +2751,95 @@ var OAuthAPI = class {
|
|
|
2700
2751
|
this.signer = new Signer();
|
|
2701
2752
|
return { kid: this.signer.kid };
|
|
2702
2753
|
}
|
|
2703
|
-
|
|
2754
|
+
/**
|
|
2755
|
+
* Withdraws one client's consent. When the client registered `apple.notificationUrl` and held
|
|
2756
|
+
* the consent, Apple's `consent-revoked` notification is delivered before this resolves.
|
|
2757
|
+
*/
|
|
2758
|
+
async revokeConsent(clientId, accountId, issuer) {
|
|
2759
|
+
const targets = this.notifiable(accountId).filter((t) => t.client.id === clientId);
|
|
2760
|
+
this.forget(clientId, accountId);
|
|
2761
|
+
return this.notify(targets, "consent-revoked", issuer);
|
|
2762
|
+
}
|
|
2763
|
+
/**
|
|
2764
|
+
* Deletes an account with its grants and sessions, after telling every client that held a
|
|
2765
|
+
* consent (`account-delete`).
|
|
2766
|
+
*/
|
|
2767
|
+
async deleteAccount(accountId, issuer) {
|
|
2768
|
+
if (!this.accounts.has(accountId)) throw new Error("Unknown account");
|
|
2769
|
+
const targets = this.notifiable(accountId);
|
|
2770
|
+
for (const { value: client } of this.clients.list()) this.forget(client.id, accountId);
|
|
2771
|
+
for (const row of this.codes.list({ where: (c) => c.accountId === accountId }))
|
|
2772
|
+
this.codes.delete(row.id);
|
|
2773
|
+
for (const row of this.tokens.list({ where: (t) => t.accountId === accountId }))
|
|
2774
|
+
this.tokens.delete(row.id);
|
|
2775
|
+
for (const row of this.transactions.list({ where: (t) => t.accountId === accountId }))
|
|
2776
|
+
this.transactions.delete(row.id);
|
|
2777
|
+
for (const row of this.sessions.list({ where: (s) => s.accountId === accountId }))
|
|
2778
|
+
this.sessions.delete(row.id);
|
|
2779
|
+
this.accounts.delete(accountId);
|
|
2780
|
+
return this.notify(targets, "account-delete", issuer);
|
|
2781
|
+
}
|
|
2782
|
+
/**
|
|
2783
|
+
* Tells every client whose identity for the account is a private relay address that the user
|
|
2784
|
+
* turned forwarding off (`email-disabled`) or on (`email-enabled`).
|
|
2785
|
+
*/
|
|
2786
|
+
async setRelayForwarding(accountId, forwarding, issuer) {
|
|
2787
|
+
if (!this.accounts.has(accountId)) throw new Error("Unknown account");
|
|
2788
|
+
return this.notify(
|
|
2789
|
+
this.notifiable(accountId).filter((t) => t.relay),
|
|
2790
|
+
forwarding ? "email-enabled" : "email-disabled",
|
|
2791
|
+
issuer,
|
|
2792
|
+
true
|
|
2793
|
+
);
|
|
2794
|
+
}
|
|
2795
|
+
/** Clients with a notification endpoint that hold a consent for the account. */
|
|
2796
|
+
notifiable(accountId) {
|
|
2797
|
+
return this.clients.list({ order: "oldest" }).flatMap(({ value: client }) => {
|
|
2798
|
+
const identity = this.identities.get(this.identityKey(client, accountId));
|
|
2799
|
+
return client.apple?.notificationUrl && identity && this.consents.has(JSON.stringify([client.id, accountId])) ? [{ client, sub: identity.sub, email: identity.email, relay: identity.privateEmail }] : [];
|
|
2800
|
+
});
|
|
2801
|
+
}
|
|
2802
|
+
async notify(targets, type, issuer, withEmail = false) {
|
|
2803
|
+
if (!targets.length) return [];
|
|
2804
|
+
const iss = issuer ?? this.options.issuer;
|
|
2805
|
+
if (!iss) throw new Error("A notification needs the issuer option or an issuer argument");
|
|
2806
|
+
const send = this.options.webhooks?.fetch ?? ((r) => fetch(r));
|
|
2807
|
+
const deliveries = [];
|
|
2808
|
+
for (const { client, sub, email } of targets) {
|
|
2809
|
+
const payload = await this.signer.sign({
|
|
2810
|
+
iss: iss.replace(/\/$/, ""),
|
|
2811
|
+
aud: client.id,
|
|
2812
|
+
iat: Math.floor(this.now() / 1e3),
|
|
2813
|
+
jti: random(),
|
|
2814
|
+
events: JSON.stringify({
|
|
2815
|
+
type,
|
|
2816
|
+
sub,
|
|
2817
|
+
...withEmail ? { email, is_private_email: "true" } : {},
|
|
2818
|
+
event_time: this.now()
|
|
2819
|
+
})
|
|
2820
|
+
});
|
|
2821
|
+
try {
|
|
2822
|
+
const response = await send(
|
|
2823
|
+
new Request(client.apple?.notificationUrl ?? "", {
|
|
2824
|
+
method: "POST",
|
|
2825
|
+
headers: { "content-type": "application/json" },
|
|
2826
|
+
body: JSON.stringify({ payload })
|
|
2827
|
+
})
|
|
2828
|
+
);
|
|
2829
|
+
deliveries.push({
|
|
2830
|
+
clientId: client.id,
|
|
2831
|
+
type,
|
|
2832
|
+
delivered: response.ok,
|
|
2833
|
+
status: response.status
|
|
2834
|
+
});
|
|
2835
|
+
} catch (error) {
|
|
2836
|
+
deliveries.push({ clientId: client.id, type, delivered: false, error: String(error) });
|
|
2837
|
+
}
|
|
2838
|
+
}
|
|
2839
|
+
return deliveries;
|
|
2840
|
+
}
|
|
2841
|
+
/** Drops one client's grant for an account: consent, identity, first-use disclosure, codes, tokens. */
|
|
2842
|
+
forget(clientId, accountId) {
|
|
2704
2843
|
const key = JSON.stringify([clientId, accountId]);
|
|
2705
2844
|
this.consents.delete(key);
|
|
2706
2845
|
this.refreshIssued.delete(key);
|
|
@@ -2843,13 +2982,18 @@ var OAuthAPI = class {
|
|
|
2843
2982
|
async idToken(grant, issuer, extra = {}) {
|
|
2844
2983
|
const account = this.accounts.get(grant.accountId);
|
|
2845
2984
|
if (!account) throw new Error("Account no longer exists");
|
|
2846
|
-
|
|
2985
|
+
const tokens = this.behavior.config.tokens;
|
|
2986
|
+
const skew = tokens?.idTokenClockSkewSeconds ?? 0;
|
|
2987
|
+
const iat = Math.floor(this.now() / 1e3) + skew;
|
|
2988
|
+
const unpublished = tokens?.idTokenSigningKey === "unpublished";
|
|
2989
|
+
if (unpublished) this.unpublishedSigner ??= new Signer();
|
|
2990
|
+
return (unpublished && this.unpublishedSigner || this.signer).sign({
|
|
2847
2991
|
...this.profile(account, grant),
|
|
2848
2992
|
iss: issuer,
|
|
2849
2993
|
aud: grant.clientId,
|
|
2850
|
-
iat
|
|
2851
|
-
exp:
|
|
2852
|
-
auth_time: Math.floor(grant.authTime / 1e3),
|
|
2994
|
+
iat,
|
|
2995
|
+
exp: iat + (tokens?.accessTtlSeconds ?? 3600),
|
|
2996
|
+
auth_time: Math.floor(grant.authTime / 1e3) + skew,
|
|
2853
2997
|
...grant.nonce ? { nonce: grant.nonce } : {},
|
|
2854
2998
|
...extra
|
|
2855
2999
|
});
|
|
@@ -3187,7 +3331,10 @@ var OAuthAPI = class {
|
|
|
3187
3331
|
return page(
|
|
3188
3332
|
"Session expired",
|
|
3189
3333
|
'<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
|
|
3334
|
+
400,
|
|
3335
|
+
void 0,
|
|
3336
|
+
void 0,
|
|
3337
|
+
"oauth-mock-error"
|
|
3191
3338
|
);
|
|
3192
3339
|
const accounts = () => this.accounts.list({ order: "oldest", where: (a) => !a.disabled }).map((a) => a.value);
|
|
3193
3340
|
if (request.method === "GET")
|
|
@@ -3249,6 +3396,16 @@ var OAuthAPI = class {
|
|
|
3249
3396
|
);
|
|
3250
3397
|
auth.accountId = account.id;
|
|
3251
3398
|
auth.authTime = this.now();
|
|
3399
|
+
const granted = this.consents.get(JSON.stringify([client.id, account.id]));
|
|
3400
|
+
if (this.provider === "google" && !auth.forceConsent && granted && [...scopes(auth.scope)].every((s) => scopes(granted.scope).has(s))) {
|
|
3401
|
+
this.transactions.delete(id);
|
|
3402
|
+
return this.startSession(
|
|
3403
|
+
await this.finish(auth, issuer),
|
|
3404
|
+
account.id,
|
|
3405
|
+
auth.authTime,
|
|
3406
|
+
issuer
|
|
3407
|
+
);
|
|
3408
|
+
}
|
|
3252
3409
|
this.transactions.update(id, auth);
|
|
3253
3410
|
return this.consent(id, client, account, auth, issuer);
|
|
3254
3411
|
}
|
|
@@ -3261,21 +3418,24 @@ var OAuthAPI = class {
|
|
|
3261
3418
|
if (choice && this.provider === "apple" && (this.behavior.config.apple?.emailMode ?? "choose") === "choose" && !this.identities.has(this.identityKey(client, account.id)))
|
|
3262
3419
|
auth.emailChoice = choice;
|
|
3263
3420
|
this.transactions.delete(id);
|
|
3264
|
-
|
|
3265
|
-
|
|
3266
|
-
|
|
3267
|
-
|
|
3268
|
-
|
|
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" : ""}`
|
|
3421
|
+
return this.startSession(
|
|
3422
|
+
await this.finish(auth, issuer),
|
|
3423
|
+
account.id,
|
|
3424
|
+
auth.authTime,
|
|
3425
|
+
issuer
|
|
3274
3426
|
);
|
|
3275
|
-
return result;
|
|
3276
3427
|
}
|
|
3277
3428
|
return fail("invalid_request", "Invalid interaction action");
|
|
3278
3429
|
}
|
|
3430
|
+
startSession(result, accountId, authTime, issuer) {
|
|
3431
|
+
const session = random();
|
|
3432
|
+
this.sessions.insert(session, { accountId, authTime, expires: this.now() + 864e5 });
|
|
3433
|
+
result.headers.append(
|
|
3434
|
+
this.options.cookieHeaders?.response ?? "set-cookie",
|
|
3435
|
+
`mb_session=${session}; Path=${new URL(issuer).pathname.replace(/\/$/, "") || "/"}; HttpOnly; SameSite=Lax; Max-Age=86400${issuer.startsWith("https:") ? "; Secure" : ""}`
|
|
3436
|
+
);
|
|
3437
|
+
return result;
|
|
3438
|
+
}
|
|
3279
3439
|
async finish(auth, issuer) {
|
|
3280
3440
|
const behavior = this.behavior.config;
|
|
3281
3441
|
if (auth.decisions.denyConsent || behavior.consent?.error)
|
|
@@ -3348,10 +3508,11 @@ var OAuthAPI = class {
|
|
|
3348
3508
|
values
|
|
3349
3509
|
).map(([k, v]) => `<input type="hidden" name="${escapeHtml(k)}" value="${escapeHtml(v)}">`).join(
|
|
3350
3510
|
""
|
|
3351
|
-
)}<button class="primary">Continue</button></form><script nonce="${nonce}">document.getElementById('callback').submit()</script>`,
|
|
3511
|
+
)}<button class="primary" data-testid="oauth-mock-form-post-continue">Continue</button></form><script nonce="${nonce}">document.getElementById('callback').submit()</script>`,
|
|
3352
3512
|
200,
|
|
3353
3513
|
formTarget(auth.redirectUri),
|
|
3354
|
-
nonce
|
|
3514
|
+
nonce,
|
|
3515
|
+
"oauth-mock-form-post"
|
|
3355
3516
|
);
|
|
3356
3517
|
return result;
|
|
3357
3518
|
}
|
|
@@ -3574,4 +3735,4 @@ export {
|
|
|
3574
3735
|
createMultiRuntime,
|
|
3575
3736
|
OAuthAPI
|
|
3576
3737
|
};
|
|
3577
|
-
//# sourceMappingURL=chunk-
|
|
3738
|
+
//# sourceMappingURL=chunk-XUUSJ73W.js.map
|