Skip to content

One browser identity for Connect and Observatory

Connect can hand a verified human identity to Observatory through the explicit signed-identity browser resource mode. Existing passthrough applications and API bearer delegation keep their original behavior. Observatory still owns its resource/action permissions and CSRF policy.

Configuration

Set the same browser rule's native_auth to signed-identity at the gateway and connector. On the gateway resource only, declare identity_key_env and identity_key_id. The deployment's environment_files.gateway_identity names a separate private environment file loaded only by the gateway service. Use a different 32-byte random signing key for each resource, encoded as canonical unpadded base64url. Never put key values in declarations or bundles.

Opt in through Observatory's authentication configuration:

{
  "authentication": {
    "mode": "connect",
    "connect": {
      "resource": "dashboard",
      "keys": [{"id": "dashboard-v1", "secret_env": "ANVIL_DASHBOARD_IDENTITY_KEY"}],
      "principals": {"human:OPAQUE_CONNECT_PRINCIPAL": "existing-operator"}
    }
  }
}

Replace the synthetic principal with the exact opaque ID returned by Connect's human administration surface. The mapped user must already have explicit native grants. There is no email matching, first-user administrator, or implicit API permission. Real mappings belong in private operator configuration.

At verified session bootstrap, Observatory creates an idempotent profile for the Connect principal. Unmapped profiles have no resource/action grants and cannot read fleet data. Profiles do not provide independent tenant data isolation. Explicitly mapped operators retain their configured permissions.

Request and session contract

The gateway strips caller identity headers and signs after a fresh Connect admission check. The connector accepts the assertion only over its authenticated gateway mTLS path for the fixed resource, strips ordinary identity headers again, and injects the retained assertion at the origin. Origin responses cannot return the assertion to the browser.

X-Anvil-Connect-Identity carries acai1.BASE64URL_JSON.BASE64URL_HMAC_SHA256. The MAC covers the literal acai1. prefix and encoded JSON. The closed payload contains version, issuer, key ID, opaque subject, Connect session ID/generation, principal generation, epoch, resource, public host, method, SHA-256 of the exact request URI, issue/expiry times, Connect session expiry, and a random assertion ID. It lasts at most 30 seconds and never outlives the Connect session. There are no OIDC tokens, passwords or role/action grants. Go and Python tests share a fixed wire vector.

Observatory validates every protected request and binds its Secure/HttpOnly cookie to the Connect subject/session/generations/epoch tuple. Same-origin and CSRF enforcement remain; reused mutation assertions are rejected. Password login is disabled only in Connect mode. Session bootstrap is bounded and idempotent under concurrent requests and replaces stale browser bindings.

Logout submits a same-origin POST to Connect, invalidates Connect sessions and active admissions, and presents an explicit sign-in link. Authelia's separate session may still exist; subsequent sign-in can reuse it. A leftover native cookie alone cannot authorize a request.

This deployment supports one administrative trust domain. If gateway and connector share an OS account, logical key distribution does not isolate them against compromise of a process under that account. Use separate identities and protected origins before making stronger isolation claims.

Passkeys

The optional managed authelia.webauthn declaration supports:

{
  "enable_passkey_login": true,
  "experimental_enable_passkey_uv_two_factors": true,
  "discoverability": "required",
  "user_verification": "required"
}

Authelia 4.39.20 accepts this configuration with its existing two_factor policy. The verified-passkey-as-two-factors option is experimental and unsupported upstream; pin and validate upgrades before activation. See Authelia's WebAuthn reference. Synced passkeys are permitted and existing recovery factors remain. The user performs enrollment and the device's biometric/PIN prompt.

1Password can store the site's passkey and offer it through its browser extension. See 1Password's instructions.

Auth portal landing

Set optional authelia.landing_resource to the ID of a declared browser resource that accepts GET, for example dashboard. After a direct Authelia login, its same-host /_anvil-connect/home default redirects with 302 to that resource's <path_prefix>/_anvil-connect/home chooser. Every enabled, provisioned Connect account can open this chooser, including a person without access to its host application. It shows only that person's current grants. Application, device approval and administration endpoints retain their separate entitlement checks. Root sign-ins return to the chooser; deeper application links keep their target.

The trampoline stays on the Authelia host because Authelia requires default_redirection_url to read and write the configured session-cookie domain. It preserves the existing narrow auth-host cookie scope; the selected browser resource then performs its normal OIDC session flow. No arbitrary URL or redirect path is accepted. See Authelia's session cookie reference.

The chooser's Change password action opens Authelia's authenticated /settings/security page; Manage passkeys opens /settings/two-factor-authentication, where Add registers another passkey. These settings links do not return through the default landing. The existing elevated-session verification still applies: with the filesystem notifier, the operator must deliver the generated verification code. With authelia.smtp, Authelia emails verification codes and forgotten-password reset links directly.

Authelia branding

The optional authelia.theme declaration accepts only light, dark, grey, oled, or auto. It only selects Authelia's supported portal preset; it does not change Connect's password, two-factor, passkey, or OIDC policy.

The optional authelia.asset_path declares a caller-provisioned directory under authelia.state_directory/assets or a single versioned child such as authelia.state_directory/assets/v1. Anvil Connect does not copy, generate, or inspect these files. The directory may contain Authelia's supported logo.png, favicon.ico, and locales/ overrides. CSS overrides are outside this contract. See Authelia's theme reference and server asset overrides reference.

Deployment and rotation

Provision the separate key without changing existing bootstrap receipts. Make Observatory accept the candidate key ID alongside the current one, then activate the gateway signer with the new ID. Verify session, direct-access denial, wrong-resource, CSRF, logout and stream revocation paths. After the old assertion lifetime plus clock skew, remove the old verifier entry. At most two verifier keys are accepted.

Auth configuration participates in the native policy digest, so changes can invalidate native sessions. Allow browser rebootstrap during rotation; do not promise uninterrupted mutations. Roll back configuration and verified binaries together while preserving current revocations, databases and profiles.