git push fails because the NIP-98 credential is scoped to discovery GET and is not sent on git-receive-pack POST
- Dominant language
- Rust
- Stars
- 32.7k
- Forks
- 4.3k
- Avg merge
- 1d 13h
- Merged PRs (30d)
- 253
Description
**Describe the bug**
Pushing to a Buzz-hosted Git repository fails with HTTP 401 even when repository ownership, relay authorization, and signing credentials are valid. Authentication succeeds for receive-pack discovery, but Git sends the subsequent streamed POST without an Authorization header. The relay challenges that POST, but Git cannot replay it after receiving the challenge.
**Steps to reproduce**
1. Configure a valid Buzz repository remote and the `git-credential-nostr` credential helper.
2. Push a branch with `git push`.
3. Inspect the HTTP exchange:
1. Git probes `GET /git///info/refs?service=git-receive-pack`.
2. The relay responds with a Nostr authentication challenge scoped to GET.
3. `git-credential-nostr` generates a GET-scoped NIP-98 credential; Git retries discovery and receives HTTP 200.
4. Git sends `POST /git///git-receive-pack` without an Authorization header.
5. The relay responds with HTTP 401 and `WWW-Authenticate: Nostr realm="buzz", method="POST"`.
6. The push aborts because Git cannot replay the streamed POST after the challenge.
**Expected behavior**
A valid push should authenticate the `git-receive-pack` POST preemptively with a fresh, POST-scoped NIP-98 credential and complete without a 401 challenge.
**Version and platform**
- Buzz version: unknown
- OS: macOS
- Git: 2.50.1
- Buzz Git relay using NIP-98 authentication
- `git-credential-nostr` credential helper
**Logs / additional context**
Root-cause evidence:
- A direct POST carrying a helper-generated, POST-scoped NIP-98 credential returns HTTP 200.
- Injecting the same kind of credential preemptively makes the push succeed:
`git -c http.extraHeader="Authorization: Nostr " push`
- The successful authenticated POST rules out repository ownership, auth-tag, relay provisioning, and repository-permission failures.
This indicates an authentication-handshake mismatch: discovery authenticates a GET, but that credential is neither valid for nor attached to the later POST. Challenging only after the streamed POST begins is too late for Git to recover.
Workaround:
Generate a fresh POST-scoped NIP-98 token and attach it preemptively using `http.extraHeader` for the push. Tokens should remain short-lived and must not be logged or persisted in repository configuration.
Recommended fix:
Before invoking `git-receive-pack`, have the Buzz Git integration attach a fresh NIP-98 Authorization header whose URL and method match the POST request. Alternatively, establish a short-lived authenticated session during discovery that is accepted by the subsequent POST.
Please also add an integration test covering the full smart-HTTP push sequence and asserting that the POST succeeds without relying on a replay after a 401 challenge.
Contributor guide
Assessment
This issue has not been assessed yet.