- Rust 94.9%
- PLpgSQL 2.3%
- Nix 1.4%
- TypeScript 0.6%
- JavaScript 0.3%
- Other 0.4%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
|
All checks were successful
Nix: Run flake checks / rust-cache-prewarm (pull_request) Successful in 41s
Nix: Run flake checks / rust-cache-prewarm (push) Successful in 1m23s
Nix: Run flake checks / nextest (pull_request) Successful in 2m33s
Nix: Run flake checks / nix-flake-check (pull_request) Successful in 3m4s
Nix: Run flake checks / nix-flake-check (push) Successful in 1m34s
Nix: Run flake checks / nextest (push) Successful in 43s
Co-developed-by: faggots<3 |
||
| .cargo | ||
| .config | ||
| .forgejo/workflows | ||
| .sqlx | ||
| .vscode | ||
| crates | ||
| doc | ||
| LICENSES | ||
| scripts | ||
| sonata-client | ||
| yaak | ||
| .example.env | ||
| .example.env.license | ||
| .git-blame-ignore-revs | ||
| .gitattributes | ||
| .gitignore | ||
| .mailmap | ||
| Cargo.lock | ||
| Cargo.lock.license | ||
| Cargo.toml | ||
| CONTRIBUTING.md | ||
| flake.lock | ||
| flake.lock.license | ||
| flake.nix | ||
| LICENSE.txt | ||
| prek.toml | ||
| prek.toml.license | ||
| README.md | ||
| REUSE.toml | ||
| rust-toolchain.toml | ||
| rustfmt.toml | ||
| sonata.toml | ||
| sqlx.toml | ||
| TODO.md | ||
Warning
This software is not yet ready to be used.
🏳️⚧️ sonata
A robust, performant implementation of a polyproto-core home server.
About
sonata is a robust, performant polyproto-core home server implementation built in Rust. It provides a complete implementation of the polyproto-core specification, handling all the routes and behaviors defined therein.
Feature overview
Note
Last updated: 2026-10-18, polyproto-core v1.0-beta.13
Below is an implementation status overview, featuring pretty much everything the
specification (v1.0-beta.13) requires and/or recommends a
polyproto-core home server to implement (if we didn't miss anything). The
Spec column links into the core specification document; normative keywords
are interpreted as described in RFC 2119 and RFC 8174.
Mentioned route paths are relative to the polyproto-core URL base
/.p2/core/v1/. Statuses are a best-effort snapshot of the current main
branch.
| Group | What it covers |
|---|---|
| Discovery and server metadata | Bootstrap endpoints every client and foreign server expects to exist, and queries first when federating |
| Identity and accounts | FIDs, personas, OIDC and SCIM provisioning, identity mapping |
| Authentication and sessions | HSATs, session records, device and bot flows, revocation |
| Certificates and cryptography | ID-Cert lifecycle, caching, key storage, algorithms |
| Sensitive actions and challenge strings | Step-up authentication and key-possession proofs |
| Realtime gateway | WebSocket events, heartbeats, resume, guaranteed delivery |
| Continuity and degraded operation | Using services while a home server is offline |
| Messaging and re-signing | Signature rules, external messages, re-signing batches |
| Migration and data portability | Redirects, export and import, deletion |
| Resources (RawR) | Content-addressed file storage with relative roots |
| Services | Discoverable service providers per actor |
| Abuse reporting | Reporting misbehaving actors |
| Transport and encoding | HTTP, IP, compression, JSON canonicalization |
Discovery and server metadata
| Feature | Description | Spec | Status |
|---|---|---|---|
.well-known/polyproto-core |
Bootstrap endpoint every client and foreign server queries first. Advertises the core API base URL and the OIDC issuer URL. | #3.1 | ✓ |
| Capabilities | GET /capabilities advertises which protocol extensions the server supports. It lists each extension's namespace ID, version, and endpoint paths. |
#3.6 | |
| Contact info | GET /contact exposes operator contact details. A required mail address and an optional admin actor FID. |
API | ✓ |
| Gateway advertisement | GET /gateway provides the WebSocket gateway URL for realtime connections. |
#3.2 |
Status legend: empty: not implemented, -: partial coverage, ✓: full implementation.
Identity and accounts
| Feature | Description | Spec | Status |
|---|---|---|---|
| Federation IDs | The localpart@domain[:port] identifier every actor is addressed by. |
#5 | - |
| Provisioning via SCIM | Account provisioning and lifecycle via SCIM 2.0 instead of polyproto routes. | #3.8, #4.2.2.3 | |
| Identity mapping | Correlates OIDC identities with SCIM-provisioned accounts through SCIM externalId. |
#4.1.1 | - |
| OIDC scopes | polyproto-specific scopes governing, for example, FID localpart changes. p2:core:fid:manage allows self-service renames through the sensitive action flow. p2:core:fid:manage:persist protects a manual localpart choice from IdP-initiated resets. |
#4.1.2 | |
| Personas | Per-actor identifiers for pseudo-identities. | #10 |
Status legend: empty: not implemented, -: partial coverage, ✓: full implementation.
Authentication and sessions
| Feature | Description | Spec | Status |
|---|---|---|---|
| Witnessed Authorization Code Flow | The login flow for sentient actors. | #3.7, #4.2.2.2 | ✓ |
| Session records | Serverside bookkeeping of every session. Tracks session ID, certificate serial, issue and last-seen times, client hint, and whether the initial ID-Cert was issued. | #4.2.1 | - |
| Foreign server authentication | Cross-server login based on key trials. GET /session/auth issues a trial and POST /session/auth exchanges a completed trial for a session token. Lets foreign servers confirm key possession and certificate provenance before permitting actions. |
#4.2.2.1 | - |
| Bots and automated clients | Sign-in path for non-sentient actors. Bots and automated services use long-lived opaque tokens outside OIDC. | #4.2.2.4 | |
| Input-constrained devices | Device authorization grant modeled on RFC 8628. POST /device/authorize issues device and user codes while POST /device/token polls for a session token. |
#4.2.2.5 | |
| Session listing and revocation | Actors manage their active sessions through these routes. GET /sessions lists them, DELETE /session ends the current session, DELETE /session/{sessionId} revokes another. Revocation takes effect synchronously and notifies remaining sessions on the gateway. |
#4.2.1 | - |
| Token revocation hook | Optional OIDC Backchannel Logout integration. The IdP can notify the home server when tokens are revoked. | #3.7 | ✓ |
Status legend: empty: not implemented, -: partial coverage, ✓: full implementation.
Certificates and cryptography
| Feature | Description | Spec | Status |
|---|---|---|---|
| ID-Cert issuance | The home server signs X.509 v3 identity certificates for actors and itself, from PKCS #10 signing requests. Certificates carry a polyproto distinguished name, polyproto constraints, and a session ID. | #6.1, #6.1.1.1, #6.1.1.2, #6.1.1.3 | - |
| Renewal and key rotation | Keeping certificates current over time. Actors renew with the same key material and keep their session | #6.1.3 | |
| Early revocation | Ending a certificate before its expiry date. The home server or the actor can revoke, which also ends the session. | #6.1.4 | |
| Serving ID-Certs | Public lookup of identity certificates. GET /idcert/server serves the server's own certificate, optionally for a past timestamp. GET /idcert/actor/{fid} serves actor certificates with timerange or session filters. |
#6.1.3 | - |
| Cacheable ID-Certs | Certificate responses that carry their own cache recency evidence. Each includes a validity window and a cacheSignature signed by the home server. Verifiers reject certificates whose signature does not check out. |
#6.4.1 | - |
| Point-in-time cache validity | Answers, whether a certificate was valid at a specific moment. Any timestamp inside the certificate's lifetime is answerable. | #6.4.2 | - |
| Cache hygiene | Keeping cached certificates healthy. A caching layer in front of the database should help take care of mass lookup traffic. | #6.4, #6.6 | - |
| Algorithms | Ed25519 is the default signature algorithm. It covers message signing and ID-Cert generation. | #6.5 | ✓ |
| Encrypted private key material | Server-side backup for key material the server cannot read. Actors upload keys encrypted client-side, download them later, and delete them if wanted. GET /session/keymaterial/size advertises the upload limit. |
#6.3 |
Status legend: empty: not implemented, -: partial coverage, ✓: full implementation.
Sensitive actions and challenge strings
| Feature | Description | Spec | Status |
|---|---|---|---|
| Sensitive action flow | Step-up re-authentication for high-risk actions. The server answers 401 with a challenge nonce, and the client retries with a fresh IdP-issued ID token in X-P2-Sensitive-Solution |
#4.3 | |
| Challenge strings | Proof of private key possession, published for third-party verification | #4.4 | - |
Status legend: empty: not implemented, -: partial coverage, ✓: full implementation.
Realtime gateway
| Feature | Description | Spec | Status |
|---|---|---|---|
| Event envelope | Uniform shape for gateway events. Every event carries a namespace, opcode, payload, and sequence number | #3.2.1 | |
| Core opcodes | The opcode set of the core namespace. Covers handshake, heartbeats, session and certificate events, resume, and service channels. | #3.2.1.2 | |
| Connection lifecycle | How a gateway connection starts and ends. | #3.2.4, #3.2.5 | |
| Heartbeats | Liveness checks between client and server. The server picks the interval, acknowledges heartbeats, and probes seemingly inactive connections before dropping them. | #3.2.2 | |
| Guaranteed delivery | Resume support for interrupted connections. On reconnect the server replays relevant missed events. Disconnections longer than two minutes are not resumable. | #3.2.6 | |
| Session and certificate events | Gateway notifications about session and certificate activity. New Session alerts every other session to a new login. Certificate invalidation and server key changes are broadcast so clients can update their state. | #3.2.3 | |
| Service channels | Multiplexing of extension events over the gateway. Clients subscribe and unsubscribe per service, and each request is acknowledged before service-specific events flow. | #3.2.3.3 | |
| Continuity mode change | Notifies a session about its continuity profile. Reports entering restricted, availability, or baseline mode, or leaving continuity | #3.2.3.10 |
Status legend: empty: not implemented, -: partial coverage, ✓: full implementation.
Continuity and degraded operation
| Feature | Description | Spec | Status |
|---|---|---|---|
| Verification states | Classification model for message trust: currentVerified, historicallyVerified, degradedContinuity, rejected, or revoked. Degraded content keeps its state until resolution. |
#4.5.1 | |
| Baseline profile | Limited offline access for existing service relationships. With the home server unreachable, foreign servers issue a baseline token that only covers re-signing operations. Full access returns once the certificate can be validated again. | #4.5.2.1 | - |
| Restricted profile | Read only continuation of an existing session during an outage. The foreign server keeps serving reads and events but accepts no new writes or authorization extensions. Triggered when cache information expires and the home server stays unreachable. | #4.5.2.2 | |
| Availability profile | Limited writes during a home server outage. After a key trial upgrade, non-sensitive writes are accepted and marked degraded | #4.5.2.3 | |
| Resolution | Settling degraded messages once evidence returns. Every accepted degraded message gets a durable record. When the home server answers again, point-in-time cache validity reclassifies each record to verified, revoked, or permanently degraded. | #4.5.3 | |
| Misuse protection | Visibility as a defense against malicious home servers. Broadcasting new sessions keeps clients aware of logins created during their absence. | #4.6 |
Status legend: empty: not implemented, -: partial coverage, ✓: full implementation.
Messaging and re-signing
| Feature | Description | Spec | Status |
|---|---|---|---|
| Signature rules | Every message carries a signature from its sender's identity key. Verification is strict; unverifiable signatures are surfaced and denied. | #6.2, #6.2.1 | |
| External messages | Messages that arrive unsigned from outside the federation. Servers flag them external so clients can render them differently from signed messages. |
#6.2.2 | |
| Re-signing | Transparent re-signing of messages after ownership transfers and key rotations. The server checks key trial proofs and the list of permitted signing keys before accepting. | #7.2 | |
| Message batches | Batch interface for re-signing of messages | #7.2.1 | |
| Server-imposed limits | Flow control for batch re-signing. Response headers cap body sizes and set the wait time between batches. Limits can change between batches. | #7.2.2 |
Status legend: empty: not implemented, -: partial coverage, ✓: full implementation.
Migration and data portability
| Feature | Description | Spec | Status |
|---|---|---|---|
| Redirects | Forwarding of request traffic after an identity migration | #7.1.1 | |
| Key trial transparency | Public audit of completed key trials. GET /keytrial/{fid} publishes them with filters for id, limit, and time range so anyone can verify migration and re-signing claims. |
#7.1.1 | - |
| Export | ??? | #7.3.2 | |
| Import | ??? | #7.3 | |
| Deletion | Erasing actor data from the server. DELETE /data removes data for the proven keys and can tear down redirects alongside. |
#7.3 | |
| Trust chain | Ownership changes build on a challenge string proof of the old keys. Old signed messages stay preserved though | #7.4 |
Status legend: empty: not implemented, -: partial coverage, ✓: full implementation.
Resources (RawR)
| Feature | Description | Spec | Status |
|---|---|---|---|
| Addressed storage | Content-addressed file storage with relative root. Upload, download, delete, and modify resources; list them with sorting and previews. RIDs must stay valid across moves, and redirects point at a new root. | #7.3.1 | |
| Access control | Per-resource visibility rules. Resources are private or public, with allow and deny lists of actor FIDs and whole instances. Public resources are served without authentication. Private resources are visible only for the uploader, and for the list of allowed viewers. | #7.3.1 | |
| Limits and quotas | Capacity and safety limits for storage. RID length is capped, uploads need a content length, and duplicates are rejected (perhaps with a URI response to the already existing resource? Spec issue). GET /resource/usage reports used and total bytes. |
#7.3.1 | |
| Ambiguous errors | Missing and forbidden resources are reported the same way on purpose. This keeps private resource existence from leaking to unauthorized/untrusted audiences | #7.3.1 | |
| Optional feature | RawR is optional for home servers. It can be disabled in sonata | #7.3.1 |
Status legend: empty: not implemented, -: partial coverage, ✓: full implementation.
Services
| Feature | Description | Spec | Status |
|---|---|---|---|
| Registration | Publishing service endpoints per actor. POST /services creates {service, url, primary} entries; DELETE /services removes them and reports any reassigned primary service. |
#9.1 | |
| Discovery | Looking up which providers an actor uses for a service. Both lookup routes are unauthenticated, and limit=1 narrows results to primary providers. |
#9.1 | |
| Primary providers | The default provider for a service namespace. Changing it is a sensitive action | #9.1.1 |
Status legend: empty: not implemented, -: partial coverage, ✓: full implementation.
Abuse reporting
| Feature | Description | Spec | Status |
|---|---|---|---|
| Abuse reports | Reporting misbehaving actors. POST /abuse accepts a report against a local or foreign actor, with identity proven by a completed key trial. The response may carry a moderator message. |
API |
Status legend: empty: not implemented, -: partial coverage, ✓: full implementation.
Transport and encoding
| Feature | Description | Spec | Status |
|---|---|---|---|
| HTTP and IP | Transport-level requirements. HTTP/1.1 at minimum with HTTP/2 recommended, and support for IPv4 and IPv6. | #3.3, #3.4 | - |
| Compression | Optional zstd compression on gateway and HTTP connections. The specification section is still WIP, so this will be an exploratory implementation | #3.5 | |
| JSON canonicalization | Signed JSON is canonicalized per RFC 8785 before signing. Signatures over non-canonical JSON fail verification. | #3.9 | - |
| Auth model | The authentication building blocks: bearer session tokens (HSAT, FSAT, BSAT), X-P2-core-keytrial for key-trial proofs, and X-P2-Sensitive-Solution for sensitive actions. |
#4.2 | - |
Status legend: empty: not implemented, -: partial coverage, ✓: full implementation.
Configuration
Sonata uses a TOML configuration file with optional SONATA_* environment
overrides. The complete reference also covers CLI options and development-only
database variables.
See the configuration reference and sonata.toml for the
available settings.
Running
Note
Please refer to the warning at the top of this file before trying to run Sonata.
Build instructions are in doc/build.md.
Contributing
Contributions are always welcome! Please read the code of conduct and the contribution guidelines first. If you have any questions or would like to stay up to date on development progress, feel free to check out the below "Community" section.
License
This project is licensed under the Mozilla Public License 2.0. See the LICENSE file for details.
Community
- Zulip: Join our community on Zulip
- Website: Visit polyproto.org
- Email: Contact us at info@polyphony.chat
🏳️⚧️ be gay, do crime!