Sitemap

Spicing Up Access: A Saucy Guide to Storacha Delegations 🌶️🔥

Storacha
6 min readApr 2, 2025

Ready to dive into how Storacha makes delegation easy? Let’s break it down. With Storacha, you don’t need to share your username and password to upload content — that’s risky! Instead, you can harness the power of . UCANs are completely decentralized and self sovereign. They eliminate the need for any central authority. Best of all, they’re unique to Storacha — putting power in the hands of users and their data.

With UCANs, You can — pun intended 😉 — delegate anything, from minimal capabilities like read only to full capabilities like read/write/delete. Recipients can even delegate capabilities to others. For example, you create a space for a team to upload their images. Once you’ve delegated to one team member, they can take it from there — approving access for others on the team as needed. Plus, UCANs are offline-first and cryptographically signed with the issuer’s key, ensuring secure, decentralized control.

You can even set certain restrictions like temporary access with an expiration time. UCANs also allow you to specify parameters to restrict actions, like store certain CIDs or uploads of a certain size. Plus, you can revoke access for enhanced security when bad actors arise.

UCANs crack open a whole world of offline permissioning magic. Will you give limited access? Will you give temporary access? Or delegate access with full permissions available? Let’s break down the best way to unlock the full potential of UCANs.

A “delegated” approach strikes a balance between full backend control and user ownership. It gives users more autonomy without adding UX complexity. Here, you authorize users via UCANs tied to their Decentralized Identifiers (DIDs).

As mentioned earlier, UCANs let you define permission scopes — like upload-only access — as well as set expiration times or revoke access entirely. Our UCAN method allows users to upload directly to Storacha. Bypassing your app’s backend and uploading to us directly will give a faster experience for the user. Also, you’ll save money by avoiding egress charges from your backend to Storacha by avoiding it entirely. Finally, Storacha will be a transparent layer because users won’t know they’re uploading to us. Implementing UCANs gives you flexibility to design the user experience you want while practicing decentralization.

We’re now going to walk you through how to build a web application where users can upload files to your Storacha space. Users will obtain a short-lived, restrictive delegation from your application backend. Your users will be able to do all of this through the power of UCANs without ever creating a Storacha account.

The chart above represents the way we will implement delegating UCANs to your users. In this example, your backend will own a registered Space in this example. You can create the registered space outside of this flow with the CLI or console. We’ve focused on a simple integration method, but there are ways you can increase complexity.

First the user will instantiate `@storacha/client`. Each user has a unique Agent that is either created or retrieved from local storage. The client does not need to log in with an email since they get their delegation directly.

When ready to upload, the application will request a delegation from your backend. This request will include the user’s Agent DID. This DID will serve to verify & identify the user. The developer can determine how this is executed.

As the owner of the registered Space, your backend will be able to use `client.createDelegation()` to generate a limited-scope UCAN delegation. In this example, we will set an expiration date/time to the UCAN delegation. This example’s delegation will allow the user to upload but not delete from the Space. The delegation is serialized with `delegration.archive()` and sent back to the user.

The user will receive the delegation that will allow them to upload to the space. The client side will deserialize the delegation and then pass that permission to the user can upload.

You can now have the user upload via `client.uploadFile()` or `client.uploadDirectory()`. Since they are authenticated and authorized, they’ll now be able to upload to the designated space.

We have a with an example for you to explore and build upon. I’ll share some code examples below and breakdown what’s happening.

In the following example, this is how you set up delegation for your users:

import * as Storage from '@web3-storage/w3up-client' // Main client for interacting with Storacha
import * as Delegation from '@web3-storage/w3up-client/delegation' // Handles decoding delegation tokens
import * as dagJSON from '@ipld/dag-json' // Used for encoding data in DAG JSON format

const storage = await Storage.create()

// Application server URL (server issuing delegation tokens)
const appServerEndpoint = `http://localhost:3000/delegation`

// Grab necessary DOM elements
const formEl = document.getElementById('form') // <form id="form">
const fileEl = document.getElementById('file') // <input id="file" type="file">

/**
* Configure an invocation by requesting a delegation token from the app server.
* @param {Array<{ can: string, nb?: unknown }>} caps - List of capabilities the client requires.
*/
const configure = async caps => {
// Encode the client's DID and requested capabilities.
const body = dagJSON.encode({ audience: storage.did(), caps })
// Request delegation from the server
// ⚠️⚠️⚠️
// TODO: Add application authorization details so your application doesn't
// just give out tokens to anyone that asks for one!
// ⚠️⚠️⚠️
const res = await fetch(appServerEndpoint, { method: 'POST', body })
// Extract the delegation from the CAR file in the response
const proof = await Delegation.extract(new Uint8Array(await res.arrayBuffer()))
// Log the received delegation capabilities
console.log(`received delegation for ${proof.ok.capabilities.map(c => c.can)}`)
// Extract the space DID (identifier of the storage space)
const space = proof.ok.capabilities[0].with
// Return delegation details to be used in the upload process
return { issuer: storage.agent.issuer, with: space, proofs: [proof.ok] }
}

// When HTML form is submitted, upload the file!
formEl.addEventListener('submit', async e => {
e.preventDefault()
const file = fileEl.files[0]
if (!file) return console.warn('no file selected')
const rootCID = await storage.uploadFile(configure, file)
console.log(`http://w3s.link/ipfs/${rootCID}`)
})

We also have a Node.js server example to show how that might be implemented:

import http from 'node:http'
import { Buffer } from 'node:buffer'
import * as Storage from '@web3-storage/w3up-client' // Main client for interacting with Storacha
import { StoreMemory } from '@web3-storage/w3up-client/stores/memory' // In-memory storage for client state
import * as Proof from '@web3-storage/w3up-client/proof' // Handles proofs for delegation
import * as Delegation from '@web3-storage/w3up-client/delegation' // Manages delegation of permissions
import { Signer } from '@web3-storage/w3up-client/principal/ed25519' // Cryptographic signer for authentication
import * as dagJSON from '@ipld/dag-json' // DAG-JSON encoding and decoding

// Setup storage client - parse the signing key and import the space.
const signer = Signer.parse(process.env.PRIVATE_KEY)
const storage = await Storage.create({ principal: signer, store: new StoreMemory() })
const proof = await Proof.parse(process.env.PROOF)
const space = await storage.addSpace(proof)

console.log(`Server DID: ${signer.did()}`)
console.log(`Space DID: ${space.did()}`)

// Create an HTTP server to handle delegation requests
const server = http.createServer(async (req, res) => {
// TODO: Add CORS configuration!

// Parse the request payload
const chunks = []
for await (const chunk of req) {
chunks.push(chunk)
}
const delegationReq = dagJSON.decode(Buffer.concat(chunks))

// ⚠️⚠️⚠️
// TODO: Validate the request before proceeding. Your application MUST verify
// that it is ok to issue a delegation to this agent DID!
// ⚠️⚠️⚠️
console.log(`creating delegation for: ${delegationReq.audience}`)

let totalSize = 0 // Track total storage size requested
for (const { can, nb } of delegationReq.caps) {
console.log('requested capability:', can, nb)
if (can === 'space/blob/add') {
totalSize += nb.blob.size
}
}
if (totalSize) console.log(`requested to store ${totalSize} bytes`)

// TODO: Validate that the user is allowed to upload `totalSize` more bytes!

// Create a delegation for the requested capabilities
const delegation = await Delegation.delegate({
issuer: signer, // The server acts as the issuer of the delegation
audience: { did: () => delegationReq.audience }, // The client agent requesting the delegation
capabilities: delegationReq.caps.map(c => ({ can: c.can, with: space.did(), nb: c.nb })),
proofs: storage.proofs(delegationReq.caps.map(c => ({ can: c.can, with: space.did() }))),
expiration: Math.floor(Date.now() / 1000) + (60 * 60 * 24) // 24 hours expiration
})

const archive = await delegation.archive() // Serialize delegation to CAR format
res.write(archive.ok)
res.end()
})

const port = process.env.SERVER_PORT ?? 3000
server.listen(port)
console.log(`Server listening on :${port}`)

We are excited to see what you’re building and how you’re leveraging delegations! If you have your own examples or project, we encourage you to create a PR in or share in our . Let’s work together towards self sovereign data and decentralization! 💥

Storacha
Storacha

Written by Storacha

Storacha is a decentralized hot storage network for data at scale, offering user-owned data with decentralized permissioning and leveraging Filecoin and IPFS.

No responses yet