authflow-cli 0.5.0 → 0.7.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.
Files changed (80) hide show
  1. package/README.md +84 -495
  2. package/dist/brand-mark.d.ts +1 -0
  3. package/dist/brand-mark.js +6 -0
  4. package/dist/brand-mark.js.map +1 -0
  5. package/dist/checks.js.map +1 -1
  6. package/dist/cli.js +2 -2
  7. package/dist/cli.js.map +1 -1
  8. package/dist/client-conformance.js.map +1 -1
  9. package/dist/commands/account.d.ts +2 -0
  10. package/dist/commands/account.js +105 -0
  11. package/dist/commands/account.js.map +1 -0
  12. package/dist/commands/feedback.d.ts +6 -0
  13. package/dist/commands/feedback.js +46 -0
  14. package/dist/commands/feedback.js.map +1 -0
  15. package/dist/commands/init.d.ts +7 -0
  16. package/dist/commands/init.js +50 -12
  17. package/dist/commands/init.js.map +1 -1
  18. package/dist/commands/mcp.js +11 -6
  19. package/dist/commands/mcp.js.map +1 -1
  20. package/dist/commands/plan.js +7 -7
  21. package/dist/commands/plan.js.map +1 -1
  22. package/dist/commands/probe.js +9 -5
  23. package/dist/commands/probe.js.map +1 -1
  24. package/dist/commands/register.js +25 -13
  25. package/dist/commands/register.js.map +1 -1
  26. package/dist/commands/rotate-origin-key.js +15 -10
  27. package/dist/commands/rotate-origin-key.js.map +1 -1
  28. package/dist/commands/scaffold.js +7 -4
  29. package/dist/commands/scaffold.js.map +1 -1
  30. package/dist/commands/set-domain.js.map +1 -1
  31. package/dist/commands/signup.d.ts +1 -0
  32. package/dist/commands/signup.js +4 -50
  33. package/dist/commands/signup.js.map +1 -1
  34. package/dist/config.d.ts +16 -0
  35. package/dist/config.js +58 -4
  36. package/dist/config.js.map +1 -1
  37. package/dist/credentials.d.ts +31 -0
  38. package/dist/credentials.js +223 -0
  39. package/dist/credentials.js.map +1 -0
  40. package/dist/custom-domain.js.map +1 -1
  41. package/dist/doctor.d.ts +21 -0
  42. package/dist/doctor.js +76 -19
  43. package/dist/doctor.js.map +1 -1
  44. package/dist/feedback.d.ts +75 -0
  45. package/dist/feedback.js +82 -0
  46. package/dist/feedback.js.map +1 -0
  47. package/dist/google-redirect.js.map +1 -1
  48. package/dist/integration-plans.json +80 -0
  49. package/dist/integration.d.ts +17 -23
  50. package/dist/integration.js +29 -236
  51. package/dist/integration.js.map +1 -1
  52. package/dist/login-callback.d.ts +29 -0
  53. package/dist/login-callback.js +79 -0
  54. package/dist/login-callback.js.map +1 -0
  55. package/dist/login.d.ts +26 -0
  56. package/dist/login.js +227 -0
  57. package/dist/login.js.map +1 -0
  58. package/dist/management.d.ts +28 -0
  59. package/dist/management.js +102 -0
  60. package/dist/management.js.map +1 -0
  61. package/dist/mcp/management-server.d.ts +4 -0
  62. package/dist/mcp/management-server.js +124 -0
  63. package/dist/mcp/management-server.js.map +1 -0
  64. package/dist/mcp/server.js +74 -35
  65. package/dist/mcp/server.js.map +1 -1
  66. package/dist/program.js +23 -1
  67. package/dist/program.js.map +1 -1
  68. package/dist/rail.d.ts +6 -0
  69. package/dist/rail.js +26 -0
  70. package/dist/rail.js.map +1 -1
  71. package/dist/secrets.d.ts +51 -18
  72. package/dist/secrets.js +234 -89
  73. package/dist/secrets.js.map +1 -1
  74. package/dist/status.js +10 -2
  75. package/dist/status.js.map +1 -1
  76. package/dist/surface.d.ts +1 -0
  77. package/dist/surface.js +1 -0
  78. package/dist/surface.js.map +1 -1
  79. package/dist/version.js.map +1 -1
  80. package/package.json +11 -10
@@ -0,0 +1,29 @@
1
+ import type { ServerResponse } from "node:http";
2
+ declare const pages: {
3
+ readonly received: {
4
+ readonly status: 200;
5
+ readonly title: "Authorization received — return to your terminal";
6
+ readonly description: "Authflow received your browser authorization. Return to your terminal to finish connecting.";
7
+ readonly next: "Your client will confirm when it is ready. You can close this tab.";
8
+ };
9
+ readonly declined: {
10
+ readonly status: 400;
11
+ readonly title: "Sign-in was not completed";
12
+ readonly description: "Authorization was declined or could not be completed. No new connection was saved.";
13
+ readonly next: "Return to your terminal and run authflow login when you are ready to try again.";
14
+ };
15
+ readonly invalidIssuer: {
16
+ readonly status: 400;
17
+ readonly title: "Sign-in could not be verified";
18
+ readonly description: "The authorization response came from an unexpected issuer. No new connection was saved.";
19
+ readonly next: "Return to your terminal and run authflow login again.";
20
+ };
21
+ readonly invalidCallback: {
22
+ readonly status: 400;
23
+ readonly title: "This sign-in link is not valid";
24
+ readonly description: "This response does not match the sign-in request waiting in your terminal.";
25
+ readonly next: "Use the sign-in link from your terminal to continue. You can close this tab.";
26
+ };
27
+ };
28
+ export declare function writeLoginCallback(response: ServerResponse, outcome: keyof typeof pages): void;
29
+ export {};
@@ -0,0 +1,79 @@
1
+ import { createHash } from "node:crypto";
2
+ import { brandMarkPng } from "./brand-mark.js";
3
+ // Keep this loopback page self-contained, using the Rail sign-in palette and card proportions.
4
+ // The mark is marketing's icon-48.png as a data: URI, lifted on dark backgrounds the way the
5
+ // Rail shell lifts it; the CSP allows exactly that image source and this one hashed stylesheet.
6
+ // Serve HTML: the affected Edge profile blocked plain-text callbacks after receiving them,
7
+ // while an HTML callback rendered successfully without changing OAuth or browser settings.
8
+ // Its only interpolated content is selected from the static messages below, never the OAuth URL.
9
+ const styles = `
10
+ :root { color-scheme: dark light; --canvas:#0c0e12; --surface:#14171e; --border:#2a3140; --fg:#f3f5f8; --muted:#9aa3b2; --accent:#7aa2ff; --raised:#1b1f28; }
11
+ * { box-sizing:border-box; }
12
+ body { margin:0; font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif; color:var(--fg); background:var(--canvas); background-image:radial-gradient(ellipse at 50% 0,rgba(122,162,255,.12),transparent 55%); line-height:1.55; }
13
+ .rail-shell { display:flex; flex-direction:column; align-items:center; justify-content:center; min-height:100vh; min-height:100dvh; padding:1.5rem 1.15rem 2rem; gap:1.15rem; }
14
+ .rail-brand { display:flex; align-items:center; gap:.55rem; color:var(--muted); font-size:.8125rem; font-weight:600; letter-spacing:.02em; }
15
+ .rail-brand-mark { display:block; width:1.35rem; height:1.35rem; filter:brightness(1.65) saturate(.9); }
16
+ .rail-card { width:100%; max-width:26.5rem; padding:1.75rem 1.5rem 1.45rem; border:1px solid var(--border); border-radius:1.25rem; background:var(--surface); box-shadow:0 24px 48px rgba(0,0,0,.2); }
17
+ .rail-eyebrow { margin:0 0 .45rem; color:var(--accent); font-size:.6875rem; font-weight:600; letter-spacing:.08em; text-transform:uppercase; }
18
+ h1 { margin:0; font-size:1.5rem; font-weight:600; line-height:1.25; letter-spacing:-.02em; }
19
+ .rail-lead { margin:.85rem 0 0; color:var(--muted); font-size:.9375rem; }
20
+ .rail-next { margin:1.35rem 0 0; padding:.85rem 1rem; border:1px solid var(--border); border-radius:.875rem; background:var(--raised); font-size:.875rem; }
21
+ .rail-foot { margin:0; color:var(--muted); font-size:.75rem; }
22
+ @media (prefers-color-scheme:light) { :root { --canvas:#eef0f4; --surface:#fff; --border:#d8dce3; --fg:#11141a; --muted:#5c6570; --accent:#3b6fe3; --raised:#f7f8fa; } .rail-card { box-shadow:0 18px 40px rgba(17,20,26,.08); } .rail-brand-mark { filter:none; } }
23
+ `;
24
+ const styleHash = createHash("sha256").update(styles).digest("base64");
25
+ const pages = {
26
+ received: {
27
+ // Served before the token exchange and workspace check, so it must not claim completion.
28
+ status: 200, title: "Authorization received — return to your terminal",
29
+ description: "Authflow received your browser authorization. Return to your terminal to finish connecting.",
30
+ next: "Your client will confirm when it is ready. You can close this tab.",
31
+ },
32
+ declined: {
33
+ status: 400, title: "Sign-in was not completed",
34
+ description: "Authorization was declined or could not be completed. No new connection was saved.",
35
+ next: "Return to your terminal and run authflow login when you are ready to try again.",
36
+ },
37
+ invalidIssuer: {
38
+ status: 400, title: "Sign-in could not be verified",
39
+ description: "The authorization response came from an unexpected issuer. No new connection was saved.",
40
+ next: "Return to your terminal and run authflow login again.",
41
+ },
42
+ invalidCallback: {
43
+ status: 400, title: "This sign-in link is not valid",
44
+ description: "This response does not match the sign-in request waiting in your terminal.",
45
+ next: "Use the sign-in link from your terminal to continue. You can close this tab.",
46
+ },
47
+ };
48
+ export function writeLoginCallback(response, outcome) {
49
+ const page = pages[outcome];
50
+ response.writeHead(page.status, {
51
+ "Content-Type": "text/html; charset=utf-8",
52
+ "Cache-Control": "no-store",
53
+ "Referrer-Policy": "no-referrer",
54
+ "X-Content-Type-Options": "nosniff",
55
+ "Content-Security-Policy": `default-src 'none'; style-src 'sha256-${styleHash}'; img-src data:; base-uri 'none'; form-action 'none'; frame-ancestors 'none'`,
56
+ }).end(`<!doctype html>
57
+ <html lang="en">
58
+ <head>
59
+ <meta charset="utf-8">
60
+ <meta name="viewport" content="width=device-width, initial-scale=1">
61
+ <meta name="referrer" content="no-referrer">
62
+ <title>${page.title} · Authflow</title>
63
+ <style>${styles}</style>
64
+ </head>
65
+ <body>
66
+ <div class="rail-shell">
67
+ <header class="rail-brand"><img class="rail-brand-mark" src="data:image/png;base64,${brandMarkPng}" alt="" width="48" height="48"><span>Authflow</span></header>
68
+ <main class="rail-card">
69
+ <p class="rail-eyebrow">Authflow CLI</p>
70
+ <h1>${page.title}</h1>
71
+ <p class="rail-lead">${page.description}</p>
72
+ <p class="rail-next">${page.next}</p>
73
+ </main>
74
+ <p class="rail-foot">Secured by Authflow</p>
75
+ </div>
76
+ </body>
77
+ </html>`);
78
+ }
79
+ //# sourceMappingURL=login-callback.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"login-callback.js","sourceRoot":"","sources":["../src/login-callback.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/C,+FAA+F;AAC/F,6FAA6F;AAC7F,gGAAgG;AAChG,2FAA2F;AAC3F,2FAA2F;AAC3F,iGAAiG;AACjG,MAAM,MAAM,GAAG;;;;;;;;;;;;;;CAcd,CAAC;AACF,MAAM,SAAS,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;AACvE,MAAM,KAAK,GAAG;IACZ,QAAQ,EAAE;QACR,yFAAyF;QACzF,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,kDAAkD;QACtE,WAAW,EAAE,6FAA6F;QAC1G,IAAI,EAAE,oEAAoE;KAC3E;IACD,QAAQ,EAAE;QACR,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,2BAA2B;QAC/C,WAAW,EAAE,oFAAoF;QACjG,IAAI,EAAE,iFAAiF;KACxF;IACD,aAAa,EAAE;QACb,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,+BAA+B;QACnD,WAAW,EAAE,yFAAyF;QACtG,IAAI,EAAE,uDAAuD;KAC9D;IACD,eAAe,EAAE;QACf,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,gCAAgC;QACpD,WAAW,EAAE,4EAA4E;QACzF,IAAI,EAAE,8EAA8E;KACrF;CACO,CAAC;AAEX,MAAM,UAAU,kBAAkB,CAAC,QAAwB,EAAE,OAA2B;IACtF,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC;IAC5B,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,EAAE;QAC9B,cAAc,EAAE,0BAA0B;QAC1C,eAAe,EAAE,UAAU;QAC3B,iBAAiB,EAAE,aAAa;QAChC,wBAAwB,EAAE,SAAS;QACnC,yBAAyB,EAAE,yCAAyC,SAAS,+EAA+E;KAC7J,CAAC,CAAC,GAAG,CAAC;;;;;;SAMA,IAAI,CAAC,KAAK;SACV,MAAM;;;;qFAIsE,YAAY;;;MAG3F,IAAI,CAAC,KAAK;uBACO,IAAI,CAAC,WAAW;uBAChB,IAAI,CAAC,IAAI;;;;;QAKxB,CAAC,CAAC;AACV,CAAC"}
@@ -0,0 +1,26 @@
1
+ import { type LoginCredential } from "./credentials.js";
2
+ /**
3
+ * RFC 9207 mix-up defense. An issuer that advertises the `iss` authorization-response parameter
4
+ * (Rail does) must send exactly one, matching the issuer this login started with; a response
5
+ * without it is not from that issuer's authorization endpoint. Others may omit it, but never send
6
+ * a wrong or duplicated one.
7
+ */
8
+ export declare function acceptsCallbackIssuer(values: string[], issuer: string, required: boolean): boolean;
9
+ export declare function validatedIssuer(value: string): string;
10
+ export declare function matchesOAuthState(actual: string | null, expected: string): boolean;
11
+ export declare function login(issuerValue: string, workspaceId?: string, open?: boolean): Promise<{
12
+ issuer: string;
13
+ workspace_id: string;
14
+ }>;
15
+ export declare function managementCredential(issuerValue: string): Promise<LoginCredential>;
16
+ /** What logout actually did. Without a stored login there is nothing to sign out of or revoke. */
17
+ export type LogoutResult = {
18
+ signed_out: true;
19
+ authorization_revoked: boolean;
20
+ } | {
21
+ signed_out: false;
22
+ reason: "no_login";
23
+ };
24
+ export declare function logout(issuerValue: string, options?: {
25
+ localOnly?: boolean;
26
+ }): Promise<LogoutResult>;
package/dist/login.js ADDED
@@ -0,0 +1,227 @@
1
+ import { createHash, randomBytes, timingSafeEqual } from "node:crypto";
2
+ import { createServer } from "node:http";
3
+ import { spawn } from "node:child_process";
4
+ import { once } from "node:events";
5
+ import { z } from "zod";
6
+ import { credentialStore } from "./credentials.js";
7
+ import { writeLoginCallback } from "./login-callback.js";
8
+ const metadataSchema = z.object({
9
+ issuer: z.string(), authorization_endpoint: z.string().url(), token_endpoint: z.string().url(),
10
+ registration_endpoint: z.string().url(), revocation_endpoint: z.string().url().optional(),
11
+ authorization_response_iss_parameter_supported: z.boolean().optional(),
12
+ });
13
+ /**
14
+ * RFC 9207 mix-up defense. An issuer that advertises the `iss` authorization-response parameter
15
+ * (Rail does) must send exactly one, matching the issuer this login started with; a response
16
+ * without it is not from that issuer's authorization endpoint. Others may omit it, but never send
17
+ * a wrong or duplicated one.
18
+ */
19
+ export function acceptsCallbackIssuer(values, issuer, required) {
20
+ if (values.length > 1)
21
+ return false;
22
+ if (values.length === 0)
23
+ return !required;
24
+ return values[0].replace(/\/+$/, "") === issuer;
25
+ }
26
+ const tokenSchema = z.object({ access_token: z.string().min(1), refresh_token: z.string().optional(), expires_in: z.number().positive(), token_type: z.string() });
27
+ export function validatedIssuer(value) {
28
+ const url = new URL(value);
29
+ if (url.username || url.password || url.search || url.hash || (url.protocol !== "https:" && !(url.protocol === "http:" && ["127.0.0.1", "localhost", "[::1]"].includes(url.hostname)))) {
30
+ throw new Error("The issuer must be an HTTPS URL (HTTP loopback is allowed locally).");
31
+ }
32
+ return url.href.replace(/\/+$/, "");
33
+ }
34
+ async function metadata(issuer) {
35
+ const response = await fetch(`${issuer}/.well-known/oauth-authorization-server`, { redirect: "error", signal: AbortSignal.timeout(15_000) });
36
+ if (!response.ok)
37
+ throw new Error(`Issuer discovery failed (${response.status}).`);
38
+ const result = metadataSchema.parse(await response.json());
39
+ if (result.issuer.replace(/\/+$/, "") !== issuer)
40
+ throw new Error("Discovery issuer does not match the selected issuer.");
41
+ for (const endpoint of [result.authorization_endpoint, result.token_endpoint, result.registration_endpoint, result.revocation_endpoint].filter(Boolean)) {
42
+ const url = new URL(endpoint);
43
+ if (url.origin !== new URL(issuer).origin || url.username || url.password || url.hash)
44
+ throw new Error("An OAuth endpoint is not a safe URL on the selected issuer origin.");
45
+ }
46
+ return result;
47
+ }
48
+ export function matchesOAuthState(actual, expected) {
49
+ return actual !== null && Buffer.byteLength(actual) === Buffer.byteLength(expected) && timingSafeEqual(Buffer.from(actual), Buffer.from(expected));
50
+ }
51
+ export async function login(issuerValue, workspaceId, open = true) {
52
+ const issuer = validatedIssuer(issuerValue);
53
+ // The browser step can take minutes. Holding the credential lock through it made every other
54
+ // CLI command and MCP call for this issuer give up after 45 s, so only the save is serialized.
55
+ const discovery = await metadata(issuer);
56
+ const verifier = randomBytes(48).toString("base64url");
57
+ const state = randomBytes(32).toString("base64url");
58
+ const callback = createServer();
59
+ callback.listen(0, "127.0.0.1");
60
+ await once(callback, "listening");
61
+ const address = callback.address();
62
+ if (!address || typeof address === "string")
63
+ throw new Error("Cannot open the loopback callback.");
64
+ const redirectUri = `http://127.0.0.1:${address.port}/callback`;
65
+ try {
66
+ const registration = await fetch(discovery.registration_endpoint, {
67
+ method: "POST", headers: { "Content-Type": "application/json" }, redirect: "error", signal: AbortSignal.timeout(15_000),
68
+ body: JSON.stringify({ client_name: "Authflow CLI", application_type: "native", redirect_uris: [redirectUri], grant_types: ["authorization_code", "refresh_token"], response_types: ["code"], token_endpoint_auth_method: "none" }),
69
+ });
70
+ if (!registration.ok)
71
+ throw new Error(`CLI registration failed (${registration.status}).`);
72
+ const { client_id } = z.object({ client_id: z.string() }).parse(await registration.json());
73
+ const authorize = new URL(discovery.authorization_endpoint);
74
+ authorize.search = new URLSearchParams({ client_id, redirect_uri: redirectUri, response_type: "code", scope: "management:read management:write offline_access", resource: `${issuer}/management/mcp`, code_challenge: createHash("sha256").update(verifier).digest("base64url"), code_challenge_method: "S256", state, ...(workspaceId ? { workspace_id: workspaceId } : {}) }).toString();
75
+ const code = new Promise((resolve, reject) => {
76
+ const timeout = setTimeout(() => reject(new Error("Sign-in timed out. Run authflow login again.")), 300_000);
77
+ let completed = false;
78
+ callback.on("request", (request, response) => {
79
+ let url;
80
+ try {
81
+ url = new URL(request.url ?? "/", redirectUri);
82
+ }
83
+ catch {
84
+ writeLoginCallback(response, "invalidCallback");
85
+ return;
86
+ }
87
+ if (completed || request.method !== "GET" || url.origin !== new URL(redirectUri).origin || url.pathname !== "/callback"
88
+ || request.headers.host !== `127.0.0.1:${address.port}` || url.searchParams.getAll("state").length !== 1
89
+ || !matchesOAuthState(url.searchParams.get("state"), state)) {
90
+ writeLoginCallback(response, "invalidCallback");
91
+ return;
92
+ }
93
+ completed = true;
94
+ clearTimeout(timeout);
95
+ const codeValue = url.searchParams.getAll("code").length === 1 && !url.searchParams.has("error") ? url.searchParams.get("code") : null;
96
+ if (!acceptsCallbackIssuer(url.searchParams.getAll("iss"), issuer, discovery.authorization_response_iss_parameter_supported === true)) {
97
+ writeLoginCallback(response, "invalidIssuer");
98
+ reject(new Error("Login issuer mismatch."));
99
+ return;
100
+ }
101
+ writeLoginCallback(response, codeValue ? "received" : "declined");
102
+ if (codeValue)
103
+ resolve(codeValue);
104
+ else
105
+ reject(new Error("Sign-in was declined or could not be completed."));
106
+ });
107
+ callback.on("close", () => clearTimeout(timeout));
108
+ });
109
+ process.stderr.write(`Complete sign-in in your browser:\n${authorize.href}\n`);
110
+ if (open)
111
+ openBrowser(authorize.href);
112
+ const authorizationCode = await code;
113
+ const tokenResponse = await fetch(discovery.token_endpoint, { method: "POST", redirect: "error", signal: AbortSignal.timeout(15_000), body: new URLSearchParams({ grant_type: "authorization_code", client_id, redirect_uri: redirectUri, code: authorizationCode, code_verifier: verifier, resource: `${issuer}/management/mcp` }) });
114
+ if (!tokenResponse.ok)
115
+ throw new Error(`Sign-in token exchange failed (${tokenResponse.status}).`);
116
+ const token = tokenSchema.parse(await tokenResponse.json());
117
+ if (token.token_type.toLowerCase() !== "bearer")
118
+ throw new Error("Unsupported token type.");
119
+ // Ask Rail which workspace this credential can access; never trust an unverified JWT decode.
120
+ const workspaceResponse = await fetch(`${issuer}/management/v1/workspaces`, { redirect: "error", headers: { Authorization: `Bearer ${token.access_token}` }, signal: AbortSignal.timeout(15_000) });
121
+ if (!workspaceResponse.ok)
122
+ throw new Error("The management credential has no accessible workspace.");
123
+ const workspaces = z.array(z.object({ id: z.string() })).parse(await workspaceResponse.json());
124
+ const workspace = workspaces.find(w => !workspaceId || w.id === workspaceId);
125
+ if (!workspace)
126
+ throw new Error("Create a workspace in the portal and run authflow login again.");
127
+ const credential = { issuer, client_id, access_token: token.access_token, refresh_token: token.refresh_token, expires_at: Date.now() + token.expires_in * 1000, workspace_id: workspace.id };
128
+ await credentialStore.withLock(issuer, async () => {
129
+ // An unreadable stored login is the repair case: there is nothing in it to revoke.
130
+ const previous = await credentialStore.read(issuer).catch(() => undefined);
131
+ if (previous) {
132
+ try {
133
+ await revokeLogin(issuer, previous, discovery, true);
134
+ }
135
+ catch (error) {
136
+ // Keep the earlier login, which is the only local copy of what could still revoke it, and do not
137
+ // leave the sign-in just made behind as a second live grant nothing stores.
138
+ await revokeLogin(issuer, credential, discovery).catch(() => undefined);
139
+ throw new Error(`Your previous login for this issuer could not be revoked, so it was kept and this sign-in was discarded (${error instanceof Error ? error.message : "unknown error"}) Run authflow logout, or revoke the CLI in portal account settings and then authflow logout --local-only, and sign in again.`);
140
+ }
141
+ }
142
+ await credentialStore.save(credential);
143
+ });
144
+ return { issuer, workspace_id: workspace.id };
145
+ }
146
+ finally {
147
+ callback.close();
148
+ callback.closeAllConnections();
149
+ }
150
+ }
151
+ export async function managementCredential(issuerValue) {
152
+ const issuer = validatedIssuer(issuerValue);
153
+ return credentialStore.withLock(issuer, async () => {
154
+ const credential = await credentialStore.read(issuer);
155
+ if (!credential)
156
+ throw new Error("Sign in first: authflow login --issuer <issuer>.");
157
+ return renewCredential(issuer, credential);
158
+ });
159
+ }
160
+ async function renewCredential(issuer, credential) {
161
+ if (credential.expires_at > Date.now() + 60_000)
162
+ return credential;
163
+ if (!credential.refresh_token)
164
+ throw new Error("Your login expired. Run authflow login again.");
165
+ const discovery = await metadata(issuer);
166
+ const response = await fetch(discovery.token_endpoint, { method: "POST", redirect: "error", signal: AbortSignal.timeout(15_000), body: new URLSearchParams({ grant_type: "refresh_token", client_id: credential.client_id, refresh_token: credential.refresh_token, resource: `${issuer}/management/mcp` }) });
167
+ if (!response.ok)
168
+ throw new Error(`Login renewal failed (${response.status}). Run authflow login again.`);
169
+ const token = tokenSchema.parse(await response.json());
170
+ if (token.token_type.toLowerCase() !== "bearer")
171
+ throw new Error("Unsupported token type.");
172
+ const next = { ...credential, access_token: token.access_token, refresh_token: token.refresh_token ?? credential.refresh_token, expires_at: Date.now() + token.expires_in * 1000 };
173
+ await credentialStore.save(next);
174
+ return next;
175
+ }
176
+ export async function logout(issuerValue, options = {}) {
177
+ const issuer = validatedIssuer(issuerValue);
178
+ return credentialStore.withLock(issuer, async () => {
179
+ // Local-only cleanup is also the repair path for an unreadable stored login, so it never reads it.
180
+ if (options.localOnly) {
181
+ await credentialStore.delete(issuer);
182
+ return { signed_out: true, authorization_revoked: false };
183
+ }
184
+ const stored = await credentialStore.read(issuer);
185
+ if (!stored)
186
+ return { signed_out: false, reason: "no_login" };
187
+ await revokeLogin(issuer, stored, await metadata(issuer));
188
+ await credentialStore.delete(issuer);
189
+ return { signed_out: true, authorization_revoked: true };
190
+ });
191
+ }
192
+ /**
193
+ * Revokes a stored login on the server: its durable workspace grant, then its latest refresh and
194
+ * access tokens. Logout uses it, and so does login before it replaces an earlier login, which would
195
+ * otherwise stay valid with no local copy left to revoke it.
196
+ * `replacing` tolerates an earlier login that is already unusable (it could not be renewed and its
197
+ * access token is refused), because a user re-authenticating is often doing so for exactly that reason.
198
+ */
199
+ async function revokeLogin(issuer, stored, discovery, replacing = false) {
200
+ // A fresh access token is necessary to revoke the durable workspace grant,
201
+ // including other still-valid access tokens from this login.
202
+ let renewed = true;
203
+ const credential = await renewCredential(issuer, stored).catch(() => { renewed = false; return stored; });
204
+ if (!discovery.revocation_endpoint)
205
+ throw new Error("This issuer does not advertise revocation. Revoke the CLI in portal account settings before removing its login.");
206
+ const grantRevocation = await fetch(`${issuer}/management/v1/authorization/revoke`, {
207
+ method: "POST", redirect: "error", signal: AbortSignal.timeout(15_000), headers: { Authorization: `Bearer ${credential.access_token}` },
208
+ });
209
+ if (!grantRevocation.ok) {
210
+ if (replacing && !renewed && grantRevocation.status === 401)
211
+ return;
212
+ throw new Error("Rail could not confirm workspace authorization revocation. Retry logout, or revoke this CLI in portal account settings and then use authflow logout --local-only to clear this device.");
213
+ }
214
+ for (const token of [credential.refresh_token, credential.access_token].filter(Boolean)) {
215
+ const response = await fetch(discovery.revocation_endpoint, { method: "POST", redirect: "error", signal: AbortSignal.timeout(15_000), body: new URLSearchParams({ client_id: credential.client_id, token: token }) });
216
+ if (!response.ok)
217
+ throw new Error("Rail could not revoke this login. Retry logout or revoke the CLI from portal account settings.");
218
+ }
219
+ }
220
+ function openBrowser(url) {
221
+ const args = process.platform === "win32" ? ["url.dll,FileProtocolHandler", url] : [url];
222
+ const executable = process.platform === "win32" ? "rundll32.exe" : process.platform === "darwin" ? "open" : "xdg-open";
223
+ const child = spawn(executable, args, { stdio: "ignore", detached: true, windowsHide: true, shell: false });
224
+ child.on("error", () => process.stderr.write("Open the sign-in URL above in your browser.\n"));
225
+ child.unref();
226
+ }
227
+ //# sourceMappingURL=login.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"login.js","sourceRoot":"","sources":["../src/login.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ export declare const managementResourceActions: readonly ["verify", "publish", "disable", "domain/refresh"];
2
+ export type ManagementResourceAction = typeof managementResourceActions[number];
3
+ /** Same owner-scoped API used by the portal and hosted MCP. Never retries a write. */
4
+ export declare function managementRequest(issuer: string, path: string, method?: string, body?: unknown, query?: Record<string, string>): Promise<unknown>;
5
+ /** Only machine-readable public fields may cross into an agent's error message. */
6
+ export declare class ManagementOperationError extends Error {
7
+ readonly result: {
8
+ status: number;
9
+ error_code: string;
10
+ pending_requirements?: string[];
11
+ allowed_actions?: string[];
12
+ recovery: string;
13
+ };
14
+ /**
15
+ * The validation message of a 400 (ProblemDetails `detail`), bounded and with URL queries removed.
16
+ * Printed by the CLI to the user's terminal; deliberately not part of `result`, which tool replies use.
17
+ */
18
+ readonly detail?: string;
19
+ constructor(status: number, body: unknown, path?: string);
20
+ }
21
+ /**
22
+ * What the CLI prints for a failed command. A management failure carries what the user needs to
23
+ * act on (pending requirements, allowed actions, and for a 400 the validation message), which the
24
+ * one-line message alone used to drop.
25
+ */
26
+ export declare function cliErrorText(error: unknown): string;
27
+ export declare function currentWorkspacePath(issuer: string, workspaceId?: string): Promise<string>;
28
+ export declare function redactToolSecrets(value: unknown): unknown;
@@ -0,0 +1,102 @@
1
+ import { managementCredential } from "./login.js";
2
+ export const managementResourceActions = ["verify", "publish", "disable", "domain/refresh"];
3
+ /** Same owner-scoped API used by the portal and hosted MCP. Never retries a write. */
4
+ export async function managementRequest(issuer, path, method = "GET", body, query) {
5
+ if (!path.startsWith("/") || path.includes("..") || /[?#\\]/.test(path))
6
+ throw new Error("Invalid management path.");
7
+ const credential = await managementCredential(issuer);
8
+ const suffix = query ? `?${new URLSearchParams(query)}` : "";
9
+ const response = await fetch(`${credential.issuer}/management/v1${path}${suffix}`, {
10
+ method, redirect: "error", signal: AbortSignal.timeout(60_000),
11
+ headers: { Authorization: `Bearer ${credential.access_token}`, Accept: "application/json", ...(body === undefined ? {} : { "Content-Type": "application/json" }) },
12
+ ...(body === undefined ? {} : { body: JSON.stringify(body) }),
13
+ });
14
+ // Handle empty authentication responses before parsing. A JSON parser can include
15
+ // response excerpts in its exception, which must never become a tool message.
16
+ if (response.status === 401)
17
+ throw new Error("Your Authflow login expired or was revoked. Run authflow login again.");
18
+ if (response.status === 403)
19
+ throw new Error("This login cannot perform the requested workspace operation. Reconnect with the appropriate workspace and scopes.");
20
+ let result = null;
21
+ if (response.status !== 204) {
22
+ try {
23
+ result = await response.json();
24
+ }
25
+ catch {
26
+ // Rail answers an unknown resource with a bare 404, and a request it cannot bind with a bare
27
+ // 400. Both still have a precise recovery, which an "unreadable response" would hide.
28
+ if (response.status !== 400 && response.status !== 404)
29
+ throw new Error(`Rail returned an unreadable management response (${response.status}). Read current resource status before explicitly retrying a mutation.`);
30
+ }
31
+ }
32
+ if (!response.ok) {
33
+ // Do not print arbitrary server bodies: error details may contain a sensitive return URL.
34
+ throw new ManagementOperationError(response.status, result, path);
35
+ }
36
+ return result;
37
+ }
38
+ /** Only machine-readable public fields may cross into an agent's error message. */
39
+ export class ManagementOperationError extends Error {
40
+ result;
41
+ /**
42
+ * The validation message of a 400 (ProblemDetails `detail`), bounded and with URL queries removed.
43
+ * Printed by the CLI to the user's terminal; deliberately not part of `result`, which tool replies use.
44
+ */
45
+ detail;
46
+ constructor(status, body, path = "") {
47
+ const details = body && typeof body === "object" ? body : {};
48
+ const identifier = (value) => typeof value === "string" && /^[a-z0-9_]{1,80}$/.test(value);
49
+ const code = details.error_code ?? details.error;
50
+ const recovery = status === 400
51
+ ? "Check the supplied arguments against the tool's documented constraints, correct invalid values, and explicitly retry. Writes are never automatically retried."
52
+ : status === 404
53
+ ? path.startsWith("/docs/")
54
+ ? "No such documentation page. Find a valid path with `authflow docs search` (MCP: authflow_search_docs)."
55
+ : "Not found in this workspace. List resources with `authflow resource list` (MCP: authflow_list_resources)."
56
+ : "Read the resource's current readiness, resolve its pending requirements, and explicitly retry the intended action. Writes are never automatically retried.";
57
+ super(`Management operation failed (${status}${identifier(code) ? `: ${code}` : ""}). ${recovery}`);
58
+ this.result = { status, error_code: identifier(code) ? code : status === 400 ? "validation_failed" : status === 404 ? "not_found" : "management_operation_failed", recovery };
59
+ for (const field of ["pending_requirements", "allowed_actions"]) {
60
+ if (Array.isArray(details[field]))
61
+ this.result[field] = details[field].filter(identifier).slice(0, 50);
62
+ }
63
+ if (status === 400 && typeof details.detail === "string" && details.detail.trim())
64
+ this.detail = boundedDetail(details.detail);
65
+ }
66
+ }
67
+ const maxDetailLength = 300;
68
+ function boundedDetail(value) {
69
+ const text = value
70
+ .replace(/[\u0000-\u001f\u007f-\u009f]+/g, " ")
71
+ .replace(/\b(https?:\/\/[^\s?#]*)[?#]\S*/gi, "$1")
72
+ .replace(/\s+/g, " ")
73
+ .trim();
74
+ return text.length > maxDetailLength ? `${text.slice(0, maxDetailLength - 1)}…` : text;
75
+ }
76
+ /**
77
+ * What the CLI prints for a failed command. A management failure carries what the user needs to
78
+ * act on (pending requirements, allowed actions, and for a 400 the validation message), which the
79
+ * one-line message alone used to drop.
80
+ */
81
+ export function cliErrorText(error) {
82
+ const message = error instanceof Error ? error.message : String(error);
83
+ if (!(error instanceof ManagementOperationError))
84
+ return message;
85
+ const { recovery: _recovery, ...fields } = error.result;
86
+ return `${message}\n${JSON.stringify({ ...fields, ...(error.detail ? { detail: error.detail } : {}) }, null, 2)}`;
87
+ }
88
+ export async function currentWorkspacePath(issuer, workspaceId) {
89
+ const credential = await managementCredential(issuer);
90
+ const workspace = workspaceId ?? credential.workspace_id;
91
+ if (workspace !== credential.workspace_id)
92
+ throw new Error("This login is bound to another workspace. Run authflow login --workspace <id> to select it.");
93
+ return `/workspaces/${encodeURIComponent(workspace)}`;
94
+ }
95
+ export function redactToolSecrets(value) {
96
+ if (Array.isArray(value))
97
+ return value.map(redactToolSecrets);
98
+ if (!value || typeof value !== "object")
99
+ return value;
100
+ return Object.fromEntries(Object.entries(value).filter(([key]) => !/^(origin_api_key|admin_api_key|access_token|refresh_token|onboarding_url|stripe_url|client_secret)$/.test(key)).map(([key, item]) => [key, redactToolSecrets(item)]));
101
+ }
102
+ //# sourceMappingURL=management.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"management.js","sourceRoot":"","sources":["../src/management.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ /** Local management uses the same owner/scoped HTTP operations as the hosted MCP and portal. */
3
+ export declare function createManagementServer(): McpServer;
4
+ export declare function runManagementStdioServer(): Promise<void>;