Reference implementation of a WAIS Provider — the token issuer and user data vault for the Web Agent Interaction Standard.
Live at pod.deeger.io
A WAIS Provider is the trust anchor in the WAIS ecosystem. It:
- Authenticates humans via Google OAuth
- Stores personal data in an encrypted vault (SD-JWT credentials)
- Issues PoD tokens that agents present to sites to prove they act on behalf of a real user
- Publishes JWKS so sites can verify token signatures
- Manages API keys for programmatic access (used by MCP servers)
Human ──login──▶ WAIS Provider ──token──▶ Agent ──token+DPoP──▶ Site
│ │
└──── JWKS ────────────────────────────────────┘
(site verifies token signature)
| Endpoint | Method | Description |
|---|---|---|
/healthz |
GET | Health check + wais-pod version |
/.well-known/jwks.json |
GET | Platform public keys (ES256) |
| Endpoint | Method | Description |
|---|---|---|
/auth/login |
GET | Google OAuth redirect |
/auth/callback |
GET | OAuth callback |
/auth/logout |
GET | Clear session |
| Endpoint | Method | Description |
|---|---|---|
/api/tokens |
POST | Create PoD token (accepts dpop_jwk for DPoP binding) |
/api/tokens |
GET | List active tokens |
/api/tokens/{jti} |
DELETE | Revoke a token |
| Endpoint | Method | Description |
|---|---|---|
/api/vault/data |
POST | Store personal data + generate SD-JWT credential |
/api/vault/data |
GET | List available claim names (not values) |
/api/vault/present |
POST | Create selective disclosure presentation |
/api/vault/data |
DELETE | Delete all vault data |
| Endpoint | Method | Description |
|---|---|---|
/api/keys |
POST | Create API key |
/api/keys |
GET | List API keys (masked) |
/api/keys/{key_hash} |
DELETE | Revoke API key |
# Clone
git clone git@github.com:deegerhq/wais-platform.git
cd wais-platform
# Setup
python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
# Run (dev mode — no SECRET_KEY needed)
uvicorn wais_platform.app:app --reload --port 8000Open http://localhost:8000 — you'll see the login page.
All config via environment variables:
| Variable | Required | Default | Description |
|---|---|---|---|
SECRET_KEY |
Yes (prod) | insecure default (dev) | Session encryption key. Crashes if missing in production. |
PLATFORM_URL |
No | http://localhost:8000 |
Public URL of this platform |
GOOGLE_CLIENT_ID |
No | — | Google OAuth client ID |
GOOGLE_CLIENT_SECRET |
No | — | Google OAuth client secret |
DATA_DIR |
No | ./data |
Directory for SQLite database and keys |
Generate a secret key:
python -c "import secrets; print(secrets.token_urlsafe(32))"See deploy/ for systemd unit, nginx config, and setup script.
# Deploy to server (example)
rsync -avz --exclude .venv --exclude __pycache__ --exclude .git \
--exclude 'wais_platform/data' \
./ root@your-server:/opt/wais-platform/
# IMPORTANT: exclude wais_platform/data to avoid overwriting production DB- Server: Ubuntu 24.04
- Proxy: nginx + certbot SSL
- Process: systemd (
wais-platform.service) - Database: SQLite (WAL mode) at
platform/data/platform.db - Keys: ES256 keypair auto-generated at
data/on first run
SQLite with 5 tables:
| Table | Purpose |
|---|---|
users |
Google OAuth user profiles |
tokens |
Issued PoD tokens (jti, audience, scopes, expiry) |
api_keys |
Hashed API keys for programmatic access |
vault_data |
Encrypted personal data (name, email, phone, etc.) |
vault_credentials |
SD-JWT credentials + disclosure maps |
- wais-pod — core WAIS library (token, issuer, DPoP, SD-JWT)
- FastAPI + Uvicorn — web framework
- Authlib — Google OAuth
- Jinja2 — HTML templates
wais_platform/
├── app.py # FastAPI app, all routes
├── auth.py # Google OAuth setup, session helpers, CSRF
├── keys.py # ES256 key generation, JWKS document
├── models.py # SQLite persistence (5 tables)
├── templates/ # Jinja2 HTML (login, dashboard, vault, token creation)
└── static/ # CSS
MIT — Deeger