# Trusted authentication ingress The owner supports separate retained-edge v1 and API-owned v2/v3 protocols from the [private authentication catalogue](../../../../../../../contracts/party_governance/authentication/README.md). They use the same canonical registration transaction and current eligibility guard. The retained [v1 wire contract](../../../../../../../contracts/party_governance/authentication/proto/pharos/party_governance/authentication/v1/authentication.proto) uses `request.party_governance.authentication`. Only the configured API principal can publish it. RabbitMQ validates AMQP `UserId`; the owner maps that identity to the application caller. Client-selected `AppId`, actor headers or a replayed dead letter cannot establish trust. An enrolled Themelio edge signs a compact EdDSA JWS after qualifying its OIDC signature, issuer, audience, nonce, authentication time and exact UserInfo subject. The protected header contains `alg: EdDSA`, `typ: pharos-party-authentication+jwt` and the enrolled `kid`. Claims contain `iss: themelio`, `aud: party_governance.authentication`, UUID `jti`, exact `oidc_issuer`/`oidc_subject`, integer-second `auth_time`/`iat`/`exp`, `legacy_session_ref` and optional `name`/verified `email`. The session reference is the lowercase SHA-256 hex digest of the legacy session. Expiry and authentication age are bounded to five minutes. Unknown, duplicate, null or ambiguous JSON claims are rejected. The request's command ID equals `jti`. Its evidence reference is `sha256:` followed by the lowercase hex digest of the complete signed assertion. Retrying preserves the command ID, correlation ID, assertion and reference; transport request IDs may change. Provider bearer tokens never enter this protocol. The verifier discards the assertion after producing request-scoped verified evidence. Registration prepares qualified evidence before opening the owner transaction. The transaction serialises exact identity reservation and stores the root, receipt, original decision, private fact and attribute observation together. Receipt replay retains that decision. Before returning it, the handler checks assertion freshness and current owner eligibility again. Disablement followed by re-enablement cannot make an older login decision usable. `PARTY_AUTHENTICATION_ENROLMENTS` (or its `_FILE` form) is a JSON list: ```json [ { "key_id": "themelio-login-1", "public_key": "", "attester": "themelio", "oidc_issuer": "https://configured-aai.example/realms/pharos" } ] ``` Absent enrolment disables registration. Invalid configured enrolment prevents startup. Beto holds public verification keys; the signing private key stays in the retained login edge. Configured enrolment must correspond to an exercised AAI client and its validated callback. Local cryptographic fixtures qualify the boundary implementation; they do not establish a production provider's behaviour. ## API-owned login V2 uses `request.party_governance.authentication.v2`, with a separate durable `ref.party_governance.authentications.v2` queue. Only the API broker caller has this request kind. The handler verifies that transport provenance came through this exact kind and rejects duplicate, unknown or wrongly typed Protobuf fields. `PARTY_API_AUTHENTICATION_ENROLMENTS` (or its `_FILE` form) contains the same configuration shape as v1, with `attester: api` and the API's public signing key. The key remains separate from the retained edge's key. Absent enrolment rejects v2 registration; invalid enrolment prevents startup. API assertions use `typ: pharos-party-authentication-v2+jwt`, `iss: api` and `aud: party_governance.authentication.v2`. The signed `jti` and `login_attempt_id` must match the command and login transaction. The schema permits optional `name`, verified `email` with `email_verified: true`, and `preferred_username`. These attributes establish no identity association. The current owner projection publishes its existing display name and email fields; the evidence digest binds the complete immutable assertion. Expiry and authentication age remain bounded to five minutes, with up to thirty seconds of future clock skew. Strict JSON verification rejects duplicate, unknown, null and malformed claims, unpaired surrogates and altered encodings. The private request, receipt and registration reply contain no provider credential. V2 replies use closed rejection/unavailable enums and bind success to the original login attempt. Same-command replay checks freshness and current eligibility again. An unavailable result can follow a committed registration; retry keeps the exact command, correlation, login attempt and assertion. ## Complete identity profile Fresh API logins use `request.party_governance.authentication.v3` and the separate `ref.party_governance.authentications.v3` queue. Enrol its API public keys with `PARTY_API_AUTHENTICATION_V3_ENROLMENTS` or its `_FILE` form, using the same entry shape. The v3 protected type and audience are `pharos-party-authentication-v3+jwt` and `party_governance.authentication.v3`. V3 requires `voperson_id` and accepts optional `site_username`, given and family names, preferred username, home organisation, external affiliations and entitlements. Exact strings and collection presence, order and values are retained. All claims have bounded lengths and reject controls or lossy Unicode. The complete assertion remains bounded to 16 KiB. The verified Site username schedules owner binding work separately from compatibility account-profile updates. `PARTY_SITE_BINDING_ENROLMENTS` or its `_FILE` form explicitly maps an issuer to its Site instance, for example `[{"issuer":"https://configured-aai.example/realms/pharos","instance":"icarus"}]`. Each issuer must also have v3 authentication enrolment. Without this mapping the Site binding worker creates no association. The worker rechecks the current Party generation and accepted attributes before changing one binding aggregate. Enrolling an issuer for v3 also requires stable identity on new registrations through retained routes. Existing exact legacy identities can continue until adoption; adopted identities use v3. Changed subjects for the same stable person return `recovery_required` and leave incumbent authority unchanged. A separately approved owner recovery advances the generation and fences old sessions. Conflicting stable identity associations reject login. V3 replies distinguish recovery and identity conflict. V2 maps those denials to its existing authentication-ineligible outcome. The v1/v2 wire and assertion schemas retain their original meaning. ## Provider-binding reads Qualified writes use the [private provider-binding protocol](../../../../../../../contracts/party_governance/provider_binding/README.md) and the API-only `provider_binding.v1` request kind. Configure `PARTY_PROVIDER_BINDING_ENROLMENTS` (or `_FILE`) as a JSON list containing `key_id`, unpadded base64url `public_key`, `attester: themelio-compat`, `oidc_issuer`, `provider` and `instance`. One key may have several explicit provider scopes; duplicate scopes or inconsistent key material prevent startup. The owner verifies the signed durable fact and current Party identity/generation before and after the binding transaction. Lost replies are resolved through the same immutable command; retired associations remain fenced on receipt replay. Provider-binding queries default to denied. First declare the caller and its query capability in the broker manifest, then enrol an exact provider read scope with `PARTY_PROVIDER_READ_SCOPES` (or its `_FILE` form). For the existing API caller: ```json [{"subject":"api","provider":"waldur","instance":"qualified-instance"}] ``` The subject must be a declared query principal. Empty, duplicate and unknown scope entries prevent startup. Provider and instance values retain their exact spelling. Reads by canonical binding ID resolve the retained association before authorisation, including retired bindings; the scope grants no provider writes. Source Control and Resource Provisioning have separate enrolled callers for complete Party snapshot recovery. Source Control also uses singular provider-binding repair within its explicitly enrolled provider scope. Every caller has separate durable event queues; production activation awaits the real-owner qualification. The retained v1 bridge creates a canonical session only after this response and the retained Themelio session/AUP check. Every protected request and realtime reconnect checks current Party eligibility and the legacy gate again. Authentication eligibility is separate from policy acceptance, Project membership and provider provisioning. V2 supplies canonical identity for the API-owned flow; API session issuance, the legacy policy-only read and compatibility account work retain their own activation and recovery boundaries.