Metadata-Version: 2.4
Name: vcb-verify
Version: 2.0.0
Summary: Verifiable Credential Barcode (VCB) verification for DL/ID PDF417 barcodes
Author: Subfile, LLC
License: BSD-3-Clause
Project-URL: Homepage, https://github.com/subfile-llc/vcb-verify
Project-URL: Repository, https://github.com/subfile-llc/vcb-verify
Project-URL: Issues, https://github.com/subfile-llc/vcb-verify/issues
Keywords: verifiable-credentials,vcb,pdf417,aamva,did,data-integrity,w3c
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: BSD License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Security :: Cryptography
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.12
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: cborld>=1.0.0
Requires-Dist: PyLD>=2.0.0
Requires-Dist: rdfcanon>=1.0.0
Requires-Dist: rdflib>=7.0.0
Requires-Dist: base58>=2.1.1
Requires-Dist: cryptography>=42.0.0
Requires-Dist: httpx>=0.27
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == "dev"
Requires-Dist: ruff>=0.8; extra == "dev"
Dynamic: license-file

# VCB Verify

[![CI](https://github.com/subfile-llc/vcb-verify/actions/workflows/ci.yml/badge.svg)](https://github.com/subfile-llc/vcb-verify/actions/workflows/ci.yml)
[![PyPI](https://img.shields.io/pypi/v/vcb-verify)](https://pypi.org/project/vcb-verify/)
[![Python](https://img.shields.io/pypi/pyversions/vcb-verify)](https://pypi.org/project/vcb-verify/)

> Verify [Verifiable Credential Barcodes][VCB] on DL/ID PDF417 barcodes.

## Background

[Verifiable Credential Barcodes][VCB] embed digitally signed credentials
inside PDF417 barcodes on government-issued drivers licenses and identification
cards. This library verifies those credentials: it parses the barcode,
checks the cryptographic proof, and optionally checks revocation status.

The library is jurisdiction-agnostic. Any issuer that follows the
[W3C VCB specification][VCB] can be supported by adding an `IssuerProfile`.
Built-in profiles are included for California DMV and the W3C Utopia test
vectors. Each profile bundles DID documents for offline use, but online
resolution is recommended for production to pick up key rotations. Host
allowlists on each profile restrict which remote resources can be fetched
during verification.

The API is synchronous. Python 3.12+.

## Install

```bash
pip install vcb-verify
```

Development:

```bash
git clone https://github.com/subfile-llc/vcb-verify.git
cd vcb-verify
pip install -e ".[dev]"
```

## Usage

### Basic verification

```python
from vcb_verify import verify
from vcb_verify.issuers import ca_dmv_prod_profile

scanned_data = ...  # PDF417 bytes or string from barcode scanner
result = verify(data=scanned_data, profile=ca_dmv_prod_profile())

if result.valid:
    print("Valid credential")
else:
    print(f"Invalid: {result.error}")
```

By default, barcodes without VCB data are returned as not-valid rather than
raising an error. Pass `require_vcb=True` to treat missing VCB data as a
verification failure, or use `profile.vcb_required_after` to require it
based on the credential's issued date.

### Check revocation status

```python
result = verify(
    data=scanned_data,
    profile=ca_dmv_prod_profile(),
    verify_status=True,
)
```

This uses ``profile.get_fetching_loader()`` by default. To supply a custom
fetch implementation, pass ``http_fetch=...`` to ``verify()`` or use
``profile.get_fetching_loader(http_fetch=...)`` as ``document_loader``.

### Document loaders

Verification resolves JSON-LD contexts and DID documents through a
``DocumentLoader`` callback. ``IssuerProfile.get_loader()`` provides offline
(bundled) and online (HTTP) defaults. For custom fetch behaviour, use
``build_loader(..., http_fetch=...)`` or ``profile.get_fetching_loader(http_fetch=...)``.

### Online mode

``online=True`` (and ``verify_status=True``) enables HTTP for allowlisted
remote resources such as revocation status lists. Live ``did:web``
fetch happens only when no bundled document is available.

### Debug output

```python
result = verify(
    data=scanned_data,
    profile=ca_dmv_prod_profile(),
    debug=True,
)
if result.debug:
    print(result.debug["credential"])
    print(result.debug["aamva_hash"].hex())
```

## Issuer Profiles

An `IssuerProfile` configures verification for a specific jurisdiction.

### Built-in profiles

| Profile | Function | Description |
|---------|----------|-------------|
| CA DMV Production | `ca_dmv_prod_profile()` | California production credentials |
| CA DMV UAT | `ca_dmv_uat_profile()` | California test/UAT credentials |
| W3C Utopia | `utopia_test_profile()` | W3C spec test vectors (offline only) |

```python
from vcb_verify.issuers import ca_dmv_prod_profile, ca_dmv_uat_profile, utopia_test_profile
```

### Custom profiles

```python
from vcb_verify import IssuerProfile

profile = IssuerProfile(
    name="my-state",
    issuer_identification_number="123456",
    vcb_subfile="ZC",
    vcb_field="ZCE",
    type_table={ ... },           # CBOR-LD compression table for this issuer
    allowed_hosts={"did.example.com"},
    static_documents={ ... },     # Bundled DID documents for offline mode
)
```

See the [CA DMV profile](src/vcb_verify/issuers/ca_dmv/profiles.py) for a
complete example.

## API

### `verify(data, *, profile, ...)`

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `data` | `bytes \| str` | *(required)* | PDF417 barcode data |
| `profile` | `IssuerProfile` | *(required)* | Issuer configuration |
| `require_vcb` | `bool` | `False` | Require VCB data to be present |
| `verify_status` | `bool` | `False` | Check revocation status online |
| `document_loader` | `DocumentLoader` | `None` | Override document loader (default from profile) |
| `http_fetch` | `Callable` | `None` | Custom HTTP fetch when `verify_status=True` |
| `debug` | `bool` | `False` | Include debug details in result |

**Returns:** `VerifyResult`

| Field | Type | Description |
|-------|------|-------------|
| `valid` | `bool` | `True` if the credential is valid |
| `error` | `Exception \| None` | Error details if invalid |
| `debug` | `dict \| None` | Debug details if requested |

### `IssuerProfile.get_loader(*, online=False)`

Returns a document loader for this profile.

| Mode | Behaviour |
|------|-----------|
| `online=False` (default) | Bundled static DID documents (no HTTP) |
| `online=True` | Bundled DIDs for keys; HTTP for allowlisted status / remote URLs |
| `get_fetching_loader(http_fetch=...)` | Online loader; optional ``http_fetch`` (defaults to ``default_http_fetch``) |

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `loader_timeout` | `float` | `5.0` | HTTP timeout (seconds) for online / fetching loaders |

## Contribute

```bash
pip install -e ".[dev]"
pytest
ruff check src tests
```

See [CHANGELOG.md](CHANGELOG.md) for release notes.

## License

[BSD-3-Clause](LICENSE) © [Subfile, LLC](https://github.com/subfile-llc/vcb-verify)

[VCB]: https://www.w3.org/TR/vc-barcodes-1.0/
