MCPcopy Create free account
hub / github.com/UsefulSoftwareCo/executor / registerDynamicClient

Function registerDynamicClient

packages/core/sdk/src/oauth-service.ts:1418–1505  ·  view source on GitHub ↗
(
    input: RegisterDynamicClientInput,
  )

Source from the content-addressed store, hash-verified

1416 });
1417
1418 const registerDynamicClient = (
1419 input: RegisterDynamicClientInput,
1420 ): Effect.Effect<
1421 OAuthClientSlug,
1422 OAuthRegisterDynamicError | OrgWriteDeniedError | StorageFailure
1423 > =>
1424 Effect.gen(function* () {
1425 yield* deps.guardOrgWrite(input.owner);
1426 const issuer = canonicalDcrIssuer(input.issuer, input.registrationEndpoint);
1427 // Resolved before the reuse decision: a persisted client registered with
1428 // a DIFFERENT callback must not be reused (strict servers 400 the
1429 // authorize request), so the reuse lookup compares against this value.
1430 const flowRedirectUri = input.redirectUri ?? redirectUri ?? null;
1431 const reuse = yield* decideDcrClientReuse(input, issuer, flowRedirectUri);
1432 if (reuse.existingSlug !== null) return reuse.existingSlug;
1433
1434 const slug = reuse.registrationSlug;
1435 // DCR registers our callback as the client's redirect_uri — fail loudly
1436 // if the executor has none rather than registering a localhost URL.
1437 if (flowRedirectUri == null) {
1438 return yield* new OAuthRegisterDynamicError({
1439 message: REDIRECT_URI_REQUIRED_MESSAGE,
1440 });
1441 }
1442 const authMethod = pickDcrAuthMethod(input.tokenEndpointAuthMethodsSupported);
1443 const registrationScopes = dedupeScopes([
1444 ...input.scopes,
1445 ...additionalAuthorizationLifecycleScopes(input),
1446 ]);
1447 const information = yield* registerDynamicClientDcr(
1448 {
1449 registrationEndpoint: input.registrationEndpoint,
1450 metadata: {
1451 client_name: input.clientName,
1452 redirect_uris: [flowRedirectUri],
1453 grant_types: ["authorization_code", "refresh_token"],
1454 response_types: ["code"],
1455 token_endpoint_auth_method: authMethod,
1456 application_type: isLoopbackHttpUrl(flowRedirectUri) ? "native" : "web",
1457 scope: registrationScopes.length > 0 ? registrationScopes.join(" ") : undefined,
1458 },
1459 },
1460 { httpClientLayer, endpointUrlPolicy: deps.endpointUrlPolicy },
1461 ).pipe(
1462 Effect.mapError((cause) => {
1463 // Some authorization servers (Vercel, and others that follow RFC 8252
1464 // strictly) reject anonymous Dynamic Client Registration unless the
1465 // redirect URI is loopback (http://localhost or http://127.0.0.1).
1466 // Executor registers its browser origin, so any hosted, tailnet, or
1467 // LAN origin trips `invalid_redirect_uri`. Turn that opaque RFC code
1468 // into guidance the user can act on instead of the raw error.
1469 // oxlint-disable-next-line executor/no-unknown-error-message -- boundary: OAuthDiscoveryError carries a typed `message`
1470 const rawMessage = cause.message;
1471 const message =
1472 cause.error === "invalid_redirect_uri" && !isLoopbackHttpUrl(flowRedirectUri)
1473 ? `Automatic OAuth setup failed: this server only approves loopback redirect ` +
1474 `URLs (http://localhost or http://127.0.0.1) for automatic registration, but ` +
1475 `Executor is using ${flowRedirectUri}. Register an OAuth app manually with that ` +

Callers

nothing calls this directly

Calls 7

isLoopbackHttpUrlFunction · 0.90
canonicalDcrIssuerFunction · 0.85
decideDcrClientReuseFunction · 0.85
pickDcrAuthMethodFunction · 0.85
dedupeScopesFunction · 0.85
createClientFunction · 0.70

Tested by

no test coverage detected