Proposal: Access-Controlled Blobs via Signed URLs
This proposal introduces a mechanism for gating access to blob content within ATProtocol. While blobs are traditionally public byte arrays accessible by anyone through a content identifier (CID), this extension enables access control by requiring signed URLs for protected blobs.
As ATProtocol evolves to support richer user experiences, there is a growing need to handle sensitive or access-restricted media (e.g., paid content, private media, or community-gated assets). This mechanism provides a flexible, cryptographically-verifiable way to authorize blob access without introducing heavyweight permissions infrastructure.
-
Blob Request (Unauthorized)
A client attempts to fetch a protected blob directly using an HTTP GET to the blob’s CID endpoint.
The server responds with HTTP 401 Unauthorized, indicating the blob is access-restricted.
-
Signed Access URL Generation
The client sends a request to the XRPC method com.atproto.repo.signBlob, including:
- The CID of the requested blob
- A request signed by the client’s DID key
The server verifies the signature and returns a signed URL granting time-limited access. This URL includes:
- signature - a server-generated HMAC of the URL (without the signature query string parameter)
- nonce - to prevent replay attacks
- notAfter (optional) - an expiry timestamp
- did (optional) - the identity that was granted the signed URL
-
Blob Request (Authorized)
The client uses the signed URL to make a new HTTP GET request.
If the signature and query parameters validate, the server responds with HTTP 200 OK and the blob content.
- Compatible with current blob retrieval process
- Leverages existing cryptographic identity infrastructure (DIDs, keypairs)
- No need for persistent ACLs or session state
- Enables short-lived, revocable blob access
- Maintains compatibility with decentralized, content-addressed storage systems
- The implementation must ensure nonces are single-use or time-bound to prevent replay
- Optionally, servers may impose rate limits or usage caps based on DID or IP
- Formalize com.atproto.repo.signBlob input/output schema
- Define URL signature format and validation algorithm
- Implement support in PDSs and compatible blob gateways
{
"lexicon": 1,
"id": "com.atproto.repo.signBlob",
"defs": {
"main": {
"type": "procedure",
"description": "Generates a signed URL for accessing a gated blob",
"parameters": {
"type": "params",
"properties": {
"blob": {
"type": "string",
"description": "The CID (Content Identifier) of the blob to access"
}
},
"required": ["blob"]
},
"input": {
"encoding": "application/json",
"schema": {
"type": "object",
"properties": {
"blob": {
"type": "string",
"description": "The blob that is being accessed."
}
},
"required": ["blob"]
}
},
"output": {
"encoding": "application/json",
"schema": {
"type": "object",
"properties": {
"url": {
"type": "string",
"description": "Signed URL including query parameters like signature, notAfter, did, and nonce"
}
},
"required": ["url"]
}
},
"errors": [
{
"name": "InvalidSignature",
"description": "The provided signature is invalid or cannot be verified"
},
{
"name": "BlobNotFound",
"description": "The requested blob does not exist"
},
{
"name": "UnauthorizedBlob",
"description": "The blob is not public and access is not permitted for the requester"
}
]
}
}
}
Additional thoughts and considerations.
HTTP HEADrequest to test access control and validity of blobs could be a cheap and safe pattern to encourage