@coinbase/cdp-sdk
Version:
SDK for interacting with the Coinbase Developer Platform Wallet API
125 lines • 4.74 kB
JavaScript
/*
* CDP JWT authentication and facilitator client for the x402 protocol.
*/
import { HTTPFacilitatorClient } from "@x402/core/server";
import { generateJwt } from "../auth/index.js";
import { version } from "../version.js";
/** CDP facilitator base URL. */
export const CDP_FACILITATOR_URL = "https://api.cdp.coinbase.com/platform/v2/x402";
const SDK_METADATA = {
sdkLanguage: "typescript",
source: "cdp-sdk",
sourceVersion: version,
};
/**
* Parses a base URL into the host and per-operation paths needed for JWT
* signing. Strips any trailing slash from the pathname before appending
* operation suffixes so the paths are always well-formed.
*
* @param baseUrl - The facilitator base URL to parse.
* @returns The resolved URL, JWT signing host, and per-operation paths.
* @throws {Error} If `baseUrl` is not a valid URL.
*/
const resolveFacilitatorEndpoints = (baseUrl) => {
let parsed;
try {
parsed = new URL(baseUrl);
}
catch {
throw new Error(`Invalid facilitator baseUrl "${baseUrl}": must be a valid URL (e.g. "https://api.cdp.coinbase.com/platform/v2/x402").`);
}
const basePath = parsed.pathname.replace(/\/$/, "");
return {
url: baseUrl,
host: parsed.host,
paths: {
verify: `${basePath}/verify`,
settle: `${basePath}/settle`,
supported: `${basePath}/supported`,
},
};
};
const getEndpointAuthHeaders = async (credentials, host, path, method = "POST") => {
const jwt = await generateJwt({
apiKeyId: credentials.apiKeyId,
apiKeySecret: credentials.apiKeySecret,
requestMethod: method,
requestHost: host,
requestPath: path,
});
const correlationContext = Object.entries(SDK_METADATA)
.map(([key, value]) => `${key}=${value}`)
.join(",");
return {
Authorization: `Bearer ${jwt}`,
"Correlation-Context": correlationContext,
};
};
const createCdpAuthHeaders = (credentials, host, paths) => {
return async () => {
const [verify, settle, supported] = await Promise.all([
getEndpointAuthHeaders(credentials, host, paths.verify),
getEndpointAuthHeaders(credentials, host, paths.settle),
getEndpointAuthHeaders(credentials, host, paths.supported, "GET"),
]);
return { verify, settle, supported };
};
};
/**
* Creates a CDP-authenticated x402 facilitator client.
*
* The returned client is pre-configured with the CDP hosted facilitator URL
* and CDP JWT-based authentication. It implements the `HTTPFacilitatorClient`
* interface from `@x402/core/server` and can be passed directly to
* `x402ResourceServer` as a drop-in replacement for a self-hosted facilitator.
*
* Credentials are resolved in order: explicit args → `CDP_API_KEY_ID` /
* `CDP_API_KEY_SECRET` environment variables.
*
* @param args - Optional credential overrides.
* @returns A configured `HTTPFacilitatorClient` ready for use with `x402ResourceServer`.
* @throws {Error} If neither explicit args nor environment variables provide credentials.
*
* @example
* Drop-in replacement for a self-hosted facilitator:
* ```typescript
* import { createCdpFacilitatorClient } from "@coinbase/cdp-sdk/x402";
* import { x402ResourceServer } from "@x402/core/server";
* import { ExactEvmScheme } from "@x402/evm/exact/server";
*
* // Set CDP_API_KEY_ID and CDP_API_KEY_SECRET in your environment
* const facilitator = createCdpFacilitatorClient();
*
* const server = new x402ResourceServer(facilitator)
* .register("eip155:8453", new ExactEvmScheme());
* ```
*
* @example
* Explicit credentials:
* ```typescript
* const facilitator = createCdpFacilitatorClient({
* apiKeyId: "my-key-id",
* apiKeySecret: "my-key-secret",
* });
* ```
*/
export function createCdpFacilitatorClient(args) {
const apiKeyId = args?.apiKeyId ?? process.env.CDP_API_KEY_ID;
const apiKeySecret = args?.apiKeySecret ?? process.env.CDP_API_KEY_SECRET;
const missing = [];
if (!apiKeyId)
missing.push("CDP_API_KEY_ID");
if (!apiKeySecret)
missing.push("CDP_API_KEY_SECRET");
if (missing.length > 0) {
throw new Error(`Missing required CDP credentials: ${missing.join(", ")}. ` +
"Provide them via args or set the corresponding environment variables.");
}
const credentials = { apiKeyId: apiKeyId, apiKeySecret: apiKeySecret };
const { url, host, paths } = resolveFacilitatorEndpoints(args?.baseUrl ?? CDP_FACILITATOR_URL);
return new HTTPFacilitatorClient({
url,
createAuthHeaders: createCdpAuthHeaders(credentials, host, paths),
});
}
//# sourceMappingURL=facilitator.js.map