Verified IPFS Retrieval in Browsers with @helia/verified-fetch

Verified IPFS Retrieval in Browsers with @helia/verified-fetch

# Announcing @helia/verified-fetch

The Shipyard team is thrilled to announce @helia/verified-fetch is now ready for broader adoption. Verified Fetch is a fetch (opens new window)-like library streamlining verified retrieval of IPFS content in browsers and JS runtimes, with native support for IPNS, and DNSLink resolution. Try it out (opens new window) and let us know what you think.

This blog post covers the challenges of IPFS retrieval in browsers and how @helia/verified-fetch addresses them with runnable examples. Feel free to jump ahead to Solution: Verified Fetch

# Problem: Verified IPFS retrieval in browsers is hard

IPFS stands out as the leading decentralized network for distributing content-addressed data (with CIDs), spanning a wide range of use cases such as off-chain voting (opens new window), NFTs, censorship-resistant Wikipedia (opens new window), and dapp distribution (opens new window).

However, developing web applications for the browser with an IPFS implementation capable of verified content retrieval has been an ongoing challenge for developers. The main reason lies in the inherent constraints of the Web Platform: TCP connections aren't allowed, and Certificate Authority signed certificates are required in Secure Contexts which increases the overhead to peer-to-peer retrieval. Other reasons include the apparent complexity of IPFS and the historical lack of focused tooling for verified IPFS retrieval on the Web.

For this reason, many developers use a trusted gateway and call it a day. That's understandable and speaks to the ease and utility of gateways as an abstraction of IPFS.

# IPFS Gateways are a useful abstraction for IPFS retrieval

Trusted IPFS Gateways abstract much of the complexity (peer-to-peer connectivity, content routing, content retrieval, verification) of IPFS with a straightforward HTTP API to the IPFS network:

gateway architecture diagram

The beauty of IPFS Gateways is in how simple they are to use: you append the CID to the URL of the Gateway and all IPFS magic is handled by the gateway for you.

For example, fetching an image with the CID: bafk...beom (opens new window) is as simple as constructing the URL: https://ipfs.io/ipfs/bafkreie7ohywtosou76tasm7j63yigtzxe7d5zqus4zu3j6oltvgtibeom which can be passed to the src attribute of an <img>, as follows:

image loaded from an IPFS gateway

# Trusting an IPFS Gateway without verifying is an anti-pattern

Nonetheless, fetching from a third-party IPFS gateway without verifying is an anti-pattern and goes against the principles of IPFS (opens new window).

Content addressing in IPFS frees you from the model of a single canonical source for data. This is a powerful concept and the root of IPFS' benefits: resilience, censorship resistance, and trustlessness. But, fully reaping the benefits of IPFS requires verification.

# Verification facilitates resilience and multi-source retrieval

Verifying IPFS content as part of the retrieval process allows you to fetch it from multiple sources –either providers or gateways– without trusting them because verification ensures the integrity of the data.

This comes with the downstream benefit of resilience: if one provider or gateway is unavailable, unreachable, or censored, you can still retrieve the CID from another (as long as other providers are available). A recent outage of the Unpkg CDN (opens new window) is a great example of why multi-source retrieval is useful.

# Trustless IPFS Gateways enable verification in browsers

Trustless IPFS Gateways (opens new window) have been gaining steam as a means of enabling verification and its downstream benefits with the simplicity of IPFS Gateways over HTTP. In fact, at the time of writing, most public gateways (opens new window) support Trustless Gateway responses.

Trustless IPFS Gateways' response types are fully and incrementally verifiable (opens new window): clients can decide between a raw block (opens new window) (application/vnd.ipld.raw (opens new window)) or a CAR stream (opens new window) (application/vnd.ipld.car (opens new window)).

Trustless IPFS Gateways are useful for browsers because they can be composed in a way that unleashes many of the aforementioned benefits of IPFS and content addressing.

Note: Browser constraints prevent you from opening connections to "random" addresses that don't have a CA signed certificate, making it hard to build IPFS clients for browsers that go straight to providers. Newer transport such as WebTransport (opens new window) and WebRTC-direct (opens new window) address this challenge in a way that may be able to reduce dependency on IPFS Gateways in the future.

# Solution: Verified Fetch

@helia/verified-fetch (opens new window) or simply Verified Fetch is a new JavaScript library by The Shipyard team (opens new window) that makes verified IPFS retrieval from trustless gateways easy. It's written in TypeScript with Web APIs so you can run it in browsers as well as modern JS runtimes.

It's the culmination of multiple streams of work we undertook to bring seamless and deeper IPFS integrations to browsers and improve the development experience with IPFS.

# Familiar, like the Fetch API

Verified Fetch is modeled after the Fetch API (opens new window) and returns Response object (opens new window) making it easy to adopt and reason about.

For example, fetching the CID of a JSON object is as simple as:

import { verifiedFetch } from '@helia/verified-fetch'
const resp = await verifiedFetch(
  'ipfs://baguqeeradnk3742vd3jxhurh22rgmlpcbzxvsy3vc5bzakwiktdeplwer6pa'
)
const obj = await resp.json()

Under the hood, Verified Fetch handles both fetching from trustless gateways and verification:

# Fast and Resilient Retrieval with Multiple Gateways

Verified Fetch supports retrieval from multiple trustless gateways, ensuring both performance and resilience. It comes pre-configured with three default gateways (opens new window), but can be easily customized:

import { createVerifiedFetch } from '@helia/verified-fetch'

const verifiedFetch = await createVerifiedFetch({
  gateways: ['https://trustless-gateway.link', 'https://cloudflare-ipfs.com'],
})

Mutable pointers are a powerful way to have a stable pointer that can be updated over time. In the IPFS ecosystem, there are two approaches to this: IPNS (opens new window) and DNSLink (opens new window).

Verified Fetch supports both using the ipns:// prefix, and resolves them to a CID, which in turn is fetched and verified.

# Resolving IPNS names with Verified Fetch

IPNS names are resolved using the Delegated routing over HTTP (opens new window) provided by the https://delegated-ipfs.dev endpoint (opens new window).

Note that you can deploy and configure your own Delegated Routing endpoint with someguy (opens new window).

To configure the endpoint in Verified Fetch, pass the endpoint to the routers config option:

import { createVerifiedFetch } from '@helia/verified-fetch'

const verifiedFetch = await createVerifiedFetch({
  routers: ['https://delegated-ipfs.dev'],
})

DNSLink records are resolved to a CID with a configurable DNS over HTTPS (opens new window) endpoint, which comes preconfigured to Cloudflare and Google:

Verified Fetch can also resolve ENS names (opens new window) that have the Contenthash record (opens new window) set with the help of EthDNS (opens new window) (A DNS bridge to ENS names). To do so, pass a DNS over HTTP EthDNS endpoint to the dnsResolvers option, like the one provided by eth.limo (opens new window):

import { createVerifiedFetch } from '@helia/verified-fetch'
import { dnsJsonOverHttps } from '@multiformats/dns/resolvers'

const verifiedFetch = await createVerifiedFetch({
  dnsResolvers: {
    'eth.': dnsJsonOverHttps('https://dns.eth.limo/dns-query'),
    '.': dnsJsonOverHttps('https://cloudflare-dns.com/dns-query'),
  },
})
const resp = await verifiedFetch(
  'ipns://vitalik.eth/images/scaling-files/cryptokitties.png'
)

The following example uses Verified Fetch to resolve vitalik.eth (opens new window) to a CID, fetch the CID, and verify the bytes of the image from Vitalik's website:

# Supports a wide range of data types

As you may have noticed, you can use Verified Fetch to fetch a wide range of data types. Verified Fetch abstracts much of the complexity of IPLD codecs, supporting UnixFS (opens new window), dag-cbor (opens new window), and dag-json (opens new window) out of the box. This frees you to focus on your application. The text(), .blob(), and .arrayBuffer() methods will work as expected without a detailed content type.

By default, if the response can be parsed as JSON, Verified Fetch sets the Content-Type header of the Response object to as application/json, otherwise it sets it as application/octet-stream.

You can also pass the Accept header (opens new window) to override certain (opens new window) response processing to modify the Content-Type of the response. For example, you may want to fetch a dag-cbor CID with the Accept header set to application/vnd.ipld.dag-json for easier handling in JavaScript:

Finally, since you can store any kind of file with UnixFS, if you want the Content-Type header of the Response object to be sniffed on the Magic Bytes of the retrieved binary data (opens new window), you can pass the contentTypeParser option as follows:

# Customizable

By default, Verified Fetch uses @helia/http (opens new window): a lightweight version of Helia on IPFS over HTTP with Trustless Gateways. However, you can pass an instance of Helia that is customized to your needs (opens new window). A common use-case might be when running on Node.js where you might want to lean more heavily on peer-to-peer retrieval using Bitswap over TCP. In that case, you would likely be better served by a Helia instance backed by libp2p as follows:

import { createHelia } from 'helia'
import { createVerifiedFetch } from '@helia/verified-fetch'

const verifiedFetch = await createVerifiedFetch(
  // Create a Helia instance instance backed by js-libp2p
  await createHelia()
)

# 📕 Docs & Examples

In addition to the embedded examples above, check out the README (opens new window) for a more elaborate overview of usage patterns and reconfigurability.

We also have a ready-to-run example (opens new window) showing @helia/verified-fetch in the browser handling different content types.

# What's next for Verified Fetch?

This release of Verified Fetch leans heavily on IPFS Gateways. But the journey doesn't end there. Our long-term vision is to enable direct retrieval from content providers, e.g. Kubo nodes (opens new window), which would further increase the resilience of retrievals.

Verified Fetch is already powering IPFS retrieval in the Service Worker Gateway (opens new window), a novel approach to in-browser IPFS gateways. This has given us the chance to dogfood and refine Verified Fetch.

# Try it out today

We built Verified Fetch with app developers in mind. We understand that for developers to be productive with IPFS, you need good abstractions.

We invite you to try it out and can't wait to see what you build with it 🚢.


@helia/verified-fetch docs

# Share your feedback

If you are new to Helia and mostly interested in retrievals, @helia/verified-fetch is a great place to get started.

For questions, discussions, and feedback join the IPFS Forums (opens new window) or the #ip-js (opens new window) channel in the IPFS Discord (opens new window). Finally, the Helia and Dapps Working Groups (opens new window) meet regularly to coordinate and discuss the development of the Helia and advance the tooling for Dapps in the IPFS ecosystem.

If you've already been using Helia (opens new window), please take a moment to fill out the Helia feedback survey (opens new window). Your feedback will help us understand developer needs and challenges as well as inform our priorities and shape Helia’s roadmap.


Helia Feedback Survey