Magazi is a content distribution platform that gates access to files using ATProtocol (Bluesky) identity and cryptographic proofs. download.ngerakines.me/
atprotocol appview atprotocol-attestations
Rust 87.8%
HTML 10.8%
Dockerfile 1.4%
9 1 0

Clone this repository

https://tangled.org/ngerakines.me/magazi https://tangled.org/did:plc:cbkjy5n7bk3ax2wplmtjofq2/magazi
git@tangled.org:ngerakines.me/magazi git@tangled.org:did:plc:cbkjy5n7bk3ax2wplmtjofq2/magazi

For self-hosted knots, clone URLs may differ based on your setup.

Download tar.gz
README.md

Magazi#

Magazi is a content distribution platform that gates access to files using ATProtocol (Bluesky) identity and cryptographic proofs. Users authenticate via ATProtocol OAuth, and file access is controlled through flexible JSONLogic rules that can require authentication, supporter status, or specific proof records.

Attestations#

This project uses atproto-attestation to verify cryptographic proofs and builds on top of the attestation implementation from ATProtoFans.

Attestations in ATProtocol are CID-first: records are prepared with signature metadata, serialized to DAG-CBOR, and the resulting content identifier is signed with elliptic curve cryptography. The signature includes a repository binding that prevents replay attacks across repositories.

When a user authenticates, Magazi fetches their com.atprotofans.supporter records and verifies the embedded attestations. Each supporter record contains StrongRef pointers to proof records signed by the creator and broker. These proofs are transparent and auditable—anyone can verify that support relationships are genuine.

Getting Started#

Prerequisites#

  • Rust 1.75+
  • An ATProtocol identity (DID) for the creator
  • OAuth client credentials registered with your PDS

Running#

  1. Clone the repository
  2. Create a catalog.json file defining your content (see Configuration)
  3. Set required environment variables
  4. Run the server:
cargo run

Configuration#

Configuration is environment-variable driven:

Variable Description
HTTP_PORT Server port (required)
HTTP_EXTERNAL External domain for OAuth callbacks (e.g., magazi.example.com)
HTTP_COOKIE_KEY Base64-encoded 64+ byte key for session cookies
OAUTH_CLIENT_CREDENTIALS Private signing key for OAuth client
CREATOR_IDENTITY Creator's DID (e.g., did:plc:abc123)
BROKER_IDENTITY Broker's DID for proof verification
DOWNLOAD_KEY Private key for JWT download tokens
FILES Filesystem path to stored files
CATALOG Path to catalog.json file

Catalog Format#

The catalog is a JSON array of entries:

[
  {
    "id": "bafkreif2gmzhha...",
    "name": "My File",
    "description": "Description of the file",
    "content_type": "application/pdf",
    "requirements": {}
  }
]

Access Rules#

Each catalog entry has a requirements field containing a JSONLogic rule evaluated against the user's entitlement context. The context includes:

  • authenticated - Boolean, true if user is logged in
  • did - User's decentralized identifier
  • handle - User's handle
  • supporter - Supporter record data
  • supporterProof - Cryptographic proof from creator
  • brokerProof - Cryptographic proof from broker

Examples#

Anyone can access (no requirements):

{
  "requirements": {}
}

Only logged in users can access:

{
  "requirements": {
    "!!": [{ "var": "authenticated" }]
  }
}

Only supporters can access (requires both proofs):

{
  "requirements": {
    "and": [
      { "!!": [{ "var": "supporterProof" }] },
      { "!!": [{ "var": "brokerProof" }] }
    ]
  }
}

Only a specific identity can access:

{
  "requirements": {
    "==": [{ "var": "did" }, "did:plc:specificuser123"]
  }
}

License#

MIT License

Copyright 2026 Nick Gerakines