How it works
A consent agreement is structured data with a life: created, signed, timestamped, anchored, checked, and ended. Here is each step, mapped to the reference code.
The record
Everything centers on one object: a consent agreement. It names who the data is about (the subject), who wants to process it (the processor), the specific purposes they may use it for, and the window it stays valid. Each purpose carries its own retention period, so “analytics for 30 days” and “email for 90 days” are separate, revocable things rather than one blanket yes.
from oconsent import ConsentManager
from datetime import datetime, timedelta
agreement = consent_manager.create_agreement(
subject_id="did:oc:9f2a...c41",
processor_id="acme-analytics",
purposes=[{
"id": "product-analytics",
"name": "Product analytics",
"description": "Understand which features get used",
"retention_period": 30 * 24 * 60 * 60, # 30 days
}],
valid_from=datetime.now(),
valid_until=datetime.now() + timedelta(days=365),
)
Sign
The agreement is signed with the subject’s key. That signature is what makes the record yours rather than the collector’s. A processor cannot forge a new agreement in your name, and they cannot quietly edit one after the fact without the signature breaking.
Timestamp
A signature proves who agreed. It does not prove when. oConsent attaches an independent timestamp from the NIST Randomness Beacon, with a Bitcoin source as a second anchor. The date on a record is no longer just the collector’s word against yours.
Anchor
The proof goes on a public chain through the Solidity contracts, so the registry of who agreed to what is not held by any single company. The bulky parts (descriptions, metadata) stay off-chain in IPFS and are referenced by hash, which keeps personal detail off the ledger while still making it tamper-evident.
Verify
Anyone holding a record can check it. The verifier confirms the agreement is active, that now is inside its validity window, and that it actually covers the purpose and processor in question. That check is the whole point: a regulator, an auditor, or you can run it without asking the company that collected the data.
oconsent verify-consent \
--agreement-id "did:oc:9f2a...c41" \
--purpose-id "product-analytics" \
--processor-id "acme-analytics"
Revoke or expire
A subject can revoke at any time. Consent can also expire on its own when its window closes. Both are written the same verifiable way, so “I took it back” is as provable as “I agreed.”
An honest note on the proofs
The paper describes zero-knowledge proofs that let a processor demonstrate valid consent without revealing the underlying detail. In the current code, that step is a hash-based placeholder, not a real ZK-SNARK. We are saying so here because the code says so in a comment, and because pretending otherwise would be exactly the kind of thing this project exists to fix. See the status page for the full built-versus-planned list.
Read the real thing
This page is a summary. The reference implementation is small enough to read in an afternoon, and the 2022 paper lays out the full model. If you want to help build the parts that are not done yet, start with contributing.