NIP-FI: Federated Identity Authorization (spec + formal model)#1485
NIP-FI: Federated Identity Authorization (spec + formal model)#1485tlongwell-block wants to merge 4 commits into
Conversation
Normative spec for authorizing a NIP-42/NIP-98-proven Nostr key only when a valid OIDC/JWT assertion resolves to the same active identity-to-key binding. Covers assertion transport (trusted-proxy and client-attached profiles), validation, per-domain binding bijection, enrollment modes (attested-key/provisioned/tofu), lease/session bounds, revocation and rotation, delegation composition, rejection semantics, discovery, and privacy. Companion formal model to follow on this branch. Generalizes the semantics implemented in #1476 into a provider-neutral standard per buzz-security thread 0d1aee9e. Co-authored-by: Tyler Longwell <tlongwell@block.xyz> Signed-off-by: Tyler Longwell <tlongwell@block.xyz>
Define the trust assumptions, authorization predicate, binding state machine, safety and liveness properties, and adversarial traces for federated identity authorization. Tighten the normative draft with a collision-free client assertion header and concrete NIP-11 discovery shape. Co-authored-by: Tyler Longwell <tlongwell@block.xyz> Signed-off-by: Tyler Longwell <tlongwell@block.xyz>
Two cold-read consistency fixes: the model's race clause still said a lost race must deny, contradicting the spec's exact-match-allows rule; and the spec's session text offered 'require a fresh assertion' at lease expiry, which has no defined mid-connection transport — assertions only arrive on an upgrade request. Co-authored-by: Tyler Longwell <tlongwell@block.xyz> Signed-off-by: Tyler Longwell <tlongwell@block.xyz>
Remove the model's remaining impossible mid-connection assertion refresh option so its WebSocket transition exactly matches the normative transport. Co-authored-by: Tyler Longwell <tlongwell@block.xyz> Signed-off-by: Tyler Longwell <tlongwell@block.xyz>
wesbillman
left a comment
There was a problem hiding this comment.
The revocation requirement is not enforced by the authorization transition. Revoke removes (i, k) from B_D and appends it to R_D, but Authorize only reads active bindings in B_D. On the next request for the same revoked pair, both lookups are empty, so attested-key and tofu recreate the pair and return ALLOW(created). That directly contradicts the normative text at NIP-FI.md:111 and the model's own requirement at NIP-FI-MODEL.md:137 that a fresh assertion must not reactivate a revoked pair without explicit recovery authorization.
Please make revocation history/tombstones part of the atomic authorization transition (for example, deny enrollment when (D, i, k) has a revocation record unless this invocation is an explicit recovery transition), and update the liveness statement so “unbound pair” excludes revoked pairs.
What
Adds NIP-FI: Federated Identity Authorization — a normative spec (
docs/nips/NIP-FI.md) and companion formal model (docs/nips/NIP-FI-MODEL.md) for authorizing an already-authenticated Nostr key only when a valid OIDC/JWT assertion from an external identity provider resolves to the same active identity-to-key binding.Docs only; no code changes.
Why
#1476 implements corporate identity binding for the Buzz relay. Per the buzz-security discussion (thread
0d1aee9e), the requirement is broader: anyone with Okta or a generic OAuth2 reverse proxy providing JWTs should be able to enable this class of enhanced identity auth. Without a spec, the first large deployment's configuration becomes an accidental standard. Prior-art survey (upstreamnips@8f8444d, strfry, Chorus, nostr-rs-relay, rnostr, relay.tools, NIP-46/98, Blossom) found no existing NIP or relay implementation binding a trusted IdP subject to a pubkey at relay authentication — closest shapes are NIP-05 domain verification (DNS/HTTPS polling, not request-time credentials) and NIP-46auth_url(custody UX, not relay binding).Design spine
(iss, sub)— never baresub, username, or email.attested-key(IdP carries the npub claim),provisioned(admin-created only), risk-labeledtofu.exp, tracked per authenticated key.Nostr-Federated-Identity: Bearer <JWT>(avoiding NIP-98'sAuthorizationheader).limitation.federated_identity+ optionalfederated_identityobject.Relationship to #1476
The spec generalizes #1476's semantics (reviewed at
bd822f3e) into a provider-neutral contract. One known delta: the spec requires WS leases not to outlive assertionexp; #1476 PR1 checks identity once at AUTH and defers lease expiry to its lifecycle follow-up. Spec leads implementation here.Verification