(target: Target, email: string)
| 202 | }; |
| 203 | |
| 204 | const mintBearerFlow = async (target: Target, email: string): Promise<string> => { |
| 205 | const consent = target.mcpConsent?.({ |
| 206 | label: email, |
| 207 | credentials: { email, password: "" }, |
| 208 | }); |
| 209 | if (!consent) throw new Error(`target ${target.name} has no mcpConsent strategy`); |
| 210 | |
| 211 | const mcpPath = new URL(target.mcpUrl).pathname; |
| 212 | let resourceResponse = await fetch( |
| 213 | new URL(`/.well-known/oauth-protected-resource${mcpPath}`, target.baseUrl), |
| 214 | ); |
| 215 | if (resourceResponse.status === 404) { |
| 216 | resourceResponse = await fetch( |
| 217 | new URL("/.well-known/oauth-protected-resource", target.baseUrl), |
| 218 | ); |
| 219 | } |
| 220 | const resource = await jsonFrom<{ authorization_servers?: ReadonlyArray<string> }>( |
| 221 | resourceResponse, |
| 222 | "mintBearer: protected-resource metadata", |
| 223 | ); |
| 224 | const issuer = resource.authorization_servers?.[0]; |
| 225 | if (!issuer) throw new Error("mintBearer: no authorization server advertised"); |
| 226 | const metadata = await jsonFrom<{ |
| 227 | readonly authorization_endpoint: string; |
| 228 | readonly token_endpoint: string; |
| 229 | readonly registration_endpoint: string; |
| 230 | }>( |
| 231 | await fetch(new URL("/.well-known/oauth-authorization-server", issuer)), |
| 232 | "mintBearer: authorization-server metadata", |
| 233 | ); |
| 234 | |
| 235 | const redirectUri = "http://127.0.0.1:9/callback"; |
| 236 | const registered = await jsonFrom<{ readonly client_id: string }>( |
| 237 | await fetch(metadata.registration_endpoint, { |
| 238 | method: "POST", |
| 239 | headers: { "content-type": "application/json" }, |
| 240 | body: JSON.stringify({ |
| 241 | client_name: "executor-e2e", |
| 242 | redirect_uris: [redirectUri], |
| 243 | grant_types: ["authorization_code", "refresh_token"], |
| 244 | response_types: ["code"], |
| 245 | token_endpoint_auth_method: "none", |
| 246 | }), |
| 247 | }), |
| 248 | "mintBearer: dynamic client registration", |
| 249 | ); |
| 250 | |
| 251 | const verifier = randomBytes(32).toString("base64url"); |
| 252 | const authorizeUrl = new URL(metadata.authorization_endpoint); |
| 253 | authorizeUrl.searchParams.set("client_id", registered.client_id); |
| 254 | authorizeUrl.searchParams.set("redirect_uri", redirectUri); |
| 255 | authorizeUrl.searchParams.set("response_type", "code"); |
| 256 | authorizeUrl.searchParams.set("state", randomUUID()); |
| 257 | authorizeUrl.searchParams.set( |
| 258 | "code_challenge", |
| 259 | createHash("sha256").update(verifier).digest("base64url"), |
| 260 | ); |
| 261 | authorizeUrl.searchParams.set("code_challenge_method", "S256"); |
no test coverage detected