๐Ÿ”Advanced: API-key Gated Data

Certain use cases require access to API endpoints protected by API keys. Given that SEDA is an open protocol, using API keys directly in a Data Request would expose them to the public, which is generally undesirable. To address this issue, SEDA utilizes Data Proxies. These proxies act as intermediaries between the API-key-protected endpoint and the overlay network, allowing only eligible Overlay Nodes to access the proxy. This ensures that unauthorized parties cannot access the API, securely exposing the API-key-protected endpoint without revealing the key.

For more information about Data Proxies and how to set one up, see Data Proxy.

In this walkthrough, we assume that a Data Proxy is already set up, either by you or a Data Provider of your choice.

Calling a Data Proxy Node with proxyHttpFetch is similar to using httpFetch, with a key difference in how the Overlay Node handles the request:

  1. It attaches a proof header to the request (x-seda-proof), which includes information about the eligibility of the Overlay Node.

  2. It verifies the validity of the Data Proxy's signature.

  3. It adds the public key to the Overlay Nodeโ€™s result, which is included in the tally phase.

  4. (Optional) Verifies if the signature belongs to the given public key and throws an error if it is invalid. Note: As a security measure, you should verify the signatures during the tally phase. This is because the tally phase is a deterministic environment that all Chain Validators run, ensuring the data has not been tampered with. Verification during execution does not guarantee against a rogue Overlay Node submitting an incorrect signature.

Let's see how we can use proxyHttpFetch:

import { Bytes, Console, proxyHttpFetch, OracleProgram, Process } from "@seda-protocol/as-sdk/assembly";

export class MyDataRequest extends OracleProgram {
  execution(): void {
    // proxyHttpFetch accepts the same arguments as httpFetch
    // The second argument is a public key; if set to null, the overlay node does not validate the signature
    const response = proxyHttpFetch("https://my-data-proxy.com", null, {
      method: "GET",
    });
    
    // Call the endpoint and check if the signature is from the given public key
    const responseWithPublicKey = proxyHttpFetch("https://my-data-proxy.com", "02a13c5e5dd02309d9c6395ebf6b79a389077a8ae04153bd07cd66f9743310d7be", {
      method: "GET",
    });

    // Ensure the fetch call has succeeded
    if (!response.ok) {
      Process.error(Bytes.fromUtf8String("Could not fetch API endpoint"));
    }

    Console.log(response.bytes.toUtf8String());
  }

  tally(): void {
    throw new Error("Not implemented");
  }
}

new MyDataRequest().run();

proxyHttpFetch calls return two headers with every response. You can use these in your execution result, for example, if you want to verify the signatures during the tally phase:

import {
	Bytes,
	generateProxyHttpSigningMessage,
	proxyHttpFetch,
	secp256k1Verify
} from "@seda-protocol/as-sdk/assembly";

const response = proxyHttpFetch("https://my-data-proxy.com", null, {
	method: "GET",
});

// Returns a hex-encoded signature (secp256k1 signature)
const signature = response.headers.get('x-seda-signature');
// Hex-encoded public key
const publicKey = response.headers.get('x-seda-publickey');
// This is the message that was signed by the proxy node
const message = generateProxyHttpSigningMessage("https://my-data-proxy.com", "GET", Bytes.empty(), response.bytes); 

// In the tally phase, we can then verify the signature:
const isSignatureValid = secp256k1Verify(message, Bytes.fromHexString(signature), Bytes.fromHexString(publicKey));
// Do something with isSignatureValid...

This setup ensures that you can safely call APIs requiring keys, leveraging Data Proxies for secure interaction.

Last updated