Skip to content

feat: Subscription credentials for paid gatekeeper access #121

@macterra

Description

@macterra

Summary

Add an optional subscription model for paid Archon access using Archon's own verifiable credentials as auth tokens. Customers subscribe (e.g., $1/month, $10/year), receive a SubscriptionCredential issued to a group DID, and use the credential DID as their auth token for API requests.

A new optional service called Drawbridge handles subscription auth, proxies requests to backend services, and manages resource-consuming operations like IPFS uploads.

Motivation

Per-operation micropayments (#75) are elegant but impractical for most customers. Real users want predictable pricing — subscribe once, use the API freely for the subscription period.

Rather than building a separate auth system, this uses Archon's own credential infrastructure: a verifiable credential proves the holder has an active subscription. The credential DID serves as the API auth token. This dogfoods Archon's core technology and requires no new auth mechanisms beyond credential verification.

Deployment Model

Drawbridge is entirely optional. Running your own Archon node for personal use requires no changes — the core services (gatekeeper, keymaster, hyperswarm, mediators) work exactly as they do today with no auth gateway.

Drawbridge is for operators who want to offer paid access to others. It follows the same opt-in pattern as cl-hive — a separate compose file included only when needed:

# docker-compose.yml
include:
  - docker-compose.btc-mainnet.yml
  - docker-compose.btc-signet.yml
  - docker-compose.cln-mainnet.yml
  - docker-compose.drawbridge.yml    # opt-in: adds subscription-based access

When Drawbridge is not included, clients talk directly to gatekeeper/keymaster as they do today. When included, Drawbridge sits in front as the customer-facing entry point.

Architecture

Gatekeeper-Compatible Interface

Drawbridge implements the same API interface as the Gatekeeper. Wallets already know the Gatekeeper API, so Drawbridge is a drop-in replacement — clients point at a Drawbridge URL instead of a Gatekeeper URL with zero code changes, just a config change.

This means:

  • Existing wallet code works unmodified — swap the URL, get subscription auth transparently
  • Drawbridge proxies standard Gatekeeper endpoints (DID create/resolve/update/delete, IPFS) to the actual Gatekeeper behind it
  • Drawbridge extends the interface with additional endpoints for registration, payment, and subscription management
  • The GatekeeperClient TypeScript class can target either a plain Gatekeeper or a Drawbridge — the caller doesn't need to know which

Service Responsibilities

Drawbridge orchestrates across multiple backend services:

  • Gatekeeper — DID resolution, group membership verification
  • Keymaster — credential verification (validity, expiry, revocation)
  • CLN — payment handling (Lightning invoices for subscription purchases)
  • IPFS — data uploads (delegated from gatekeeper to Drawbridge)
  • Redis — usage tracking and rate limiting
Client → Drawbridge → Gatekeeper (DID resolution, group membership)
                    → Keymaster  (credential verification)
                    → CLN        (subscription payments)
                    → IPFS       (data uploads, metered by subscription tier)
                    → Redis      (usage counters, rate limiting)

Drawbridge is the customer-facing API entry point. It handles subscription auth, enforces tier-based resource limits, and proxies authorized requests to the appropriate backend service.

Group-Based Subscription Auth

A wallet holds multiple DIDs (identities). Rather than requiring a subscription per DID, the subscription credential is issued to a group DID. The wallet automatically manages group membership — adding new DIDs when created, removing them when deleted.

This means:

  • One subscription per wallet, not per identity
  • Auth is tied to identity, not a bearer token — Drawbridge verifies the requesting DID is a member of the subscription group
  • A leaked credential DID is useless without a DID that's actually in the group
  • The user never thinks about subscription management — the wallet handles group membership transparently

Usage Tracking (Redis)

Drawbridge uses Redis (already in the stack) to track per-subscription usage:

  • drawbridge:usage:{credentialDid}:dids:{month} — DIDs created this month
  • drawbridge:usage:{credentialDid}:uploads:{month} — bytes uploaded this month
  • drawbridge:ratelimit:{credentialDid} — sliding window request counter

Usage is tracked per subscription credential DID (shared across all DIDs in the group), not per individual identity DID. Keys use TTL-based expiry aligned to billing periods.

IPFS Delegation

When Drawbridge is deployed, IPFS upload handling moves from the gatekeeper to Drawbridge. Storage has real costs (disk, bandwidth, pinning), so routing uploads through Drawbridge makes them subscription-gated and metered by tier.

The gatekeeper retains IPFS read access (resolving CIDs for DID documents). Without Drawbridge, the gatekeeper handles uploads directly as it does today — no behavior change for personal nodes.

Wallet Bootstrap Flow

New wallets connecting to a Drawbridge-protected node need zero prior state. The bootstrap is a single round-trip:

  1. Wallet connects to the Drawbridge URL, makes a request
  2. Drawbridge returns HTTP 402 with subscription info (available tiers, pricing, payment methods)
  3. Wallet has no subscription credential — requests a free-tier registration from Drawbridge's unauthenticated registration endpoint
  4. Drawbridge bootstraps everything in one operation:
    a. Creates a new DID for the wallet
    b. Creates a group DID owned by the new DID
    c. Adds the new DID to the group
    d. Issues a free-tier SubscriptionCredential to the group DID
  5. Wallet receives the credential — everything it needs is derivable from that single credential: its DID, the group DID (credential holder), and the subscription credential DID
  6. Subsequent requests include the credential DID + requesting DID, normal auth flow takes over

For existing wallets (already have DIDs from another node), the flow skips step 4a — the wallet presents its existing DID, Drawbridge creates the group and credential around it.

Adding future DIDs to the subscription is automatic — the wallet adds new DIDs to the group it already owns. No re-registration needed.

Upgrade Flow

  1. Wallet requests an upgrade (e.g., free → pro)
  2. Drawbridge returns a Lightning invoice for the subscription price
  3. Wallet pays the invoice
  4. Drawbridge updates the SubscriptionCredential with the new tier and expiry
  5. Higher limits take effect immediately

Subscription Lifecycle

Action Mechanism
Register Unauthenticated bootstrap: create DID + group + free-tier credential
Add identity Wallet adds new DID to the subscription group (group owner controls membership)
Remove identity Wallet removes DID from the subscription group
Upgrade/downgrade Update the credential with new tier and scope
Renew Update the credential with a new expiry date
Cancel Revoke the credential

SubscriptionCredential Schema

{
  "$credentialType": ["VerifiableCredential", "SubscriptionCredential"],
  "properties": {
    "tier": { "type": "string", "enum": ["free", "basic", "pro"] },
    "scope": { "type": "array", "items": { "type": "string" } },
    "registries": { "type": "array", "items": { "type": "string" } },
    "maxDidsPerMonth": { "type": "number" },
    "maxUploadBytes": { "type": "number" },
    "subscribedAt": { "type": "string", "format": "date-time" }
  },
  "required": ["tier", "scope", "subscribedAt"]
}

Example tiers:

  • free — hyperswarm operations only, no IPFS uploads, rate-limited (e.g., 10 DIDs/month)
  • basic — hyperswarm + BTC:signet, limited IPFS storage quota, higher rate limits
  • pro — all registries including BTC:mainnet, generous/unlimited IPFS uploads

Drawbridge Auth Middleware

  1. Extract credential DID and requesting DID from the request
  2. Resolve the credential via gatekeeper — verify it's a valid SubscriptionCredential
  3. Verify the credential via keymaster — check not expired, not revoked
  4. Verify group membership via gatekeeper — confirm the requesting DID is a member of the credential's holder (group DID)
  5. Check usage counters in Redis against tier limits (rate limits, DID quotas, upload quotas)
  6. Proxy the request to the backend service, or return 401 (not a group member) / 403 (insufficient scope) / 429 (rate limited)
  7. On success, increment usage counters in Redis

Relationship to L402 (#75)

L402 and subscriptions are complementary, not competing:

  • Subscriptions — ongoing access for regular customers
  • L402 — pay-as-you-go for one-off operations, anonymous access, or agent-to-agent commerce
  • L402 could be the payment mechanism for purchasing a subscription (pay Lightning invoice → receive credential)

Prerequisites

  • feat: Add @didcid/cl-hive client package #120@didcid/cl-hive client package (for Lightning payment handling)
  • Group DID support (create group, add/remove members, check membership)
  • Credential update support for renewals and tier changes
  • A credential schema for SubscriptionCredential

Enables

  • Paid Archon deployments with tiered access (opt-in, personal nodes unaffected)
  • Zero-friction onboarding (free tier in one round-trip, no prior state needed)
  • Rate-limited free tier (prevents spam without blocking access entirely)
  • Metered IPFS storage by subscription tier
  • Tiered registry access (free hyperswarm vs paid BTC:mainnet)
  • Self-sustaining node economics (subscription revenue covers on-chain TX fees and IPFS storage costs)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions