Goal
Let a caller reach Ollama Cloud without provisioning an API key, by using the
Ed25519 identity already on disk at ~/.ollama/id_ed25519 (the one ollama signin
establishes) — the keyless, zero-config path, analogous to how the Codex provider
rides a ChatGPT subscription instead of an API key.
Today (after #13) the Ollama provider supports local discovery (no auth) and
Ollama Cloud via OLLAMA_API_KEY → Authorization: Bearer <key>. This issue
tracks the keyless Ed25519 path, to be done correctly and verified.
Why the first attempt was removed in #13
#13 originally shipped a hand-rolled sources/ollama_auth.py that did not
implement Ollama's real auth. It pre-signed a self-timestamped string
({method},{url}?ts={ts}) and sent Authorization: <pubkey_b64>:<sig_b64>
directly to /api/tags. That is a different, invented protocol; its tests
were self-referential (they asserted the module's own output format, never hit
ollama.com); and failures were swallowed silently (except Exception: return []),
so "no error" looked like "it worked". It was never verified against the live
endpoint. Commit 77f8608 removed it (and the unpinned cryptography>=42.0.0
dep) and shipped the API-key path; #13 merged as that.
The original code is not lost — recover it from the pre-repair commit:
git show 9eedac2:sources/ollama_auth.py (branch history of #13).
The real protocol to implement
Ollama uses a challenge-response that ends in a Bearer token, not a direct
signed header:
- Hit the endpoint → 401 with a
WWW-Authenticate header carrying
realm, service, scope, and a server nonce.
- Sign
method + URL + server-nonce with the Ed25519 key (auth.Sign).
- POST the signature to the realm (auth server) → receive a Bearer token
(api.TokenResponse) (getAuthorizationToken).
- Use
Authorization: Bearer <token> on the actual API request.
(Reference: ollama source auth.Sign / getAuthorizationToken / registryChallenge.)
Acceptance criteria (the merge bar)
Notes
Goal
Let a caller reach Ollama Cloud without provisioning an API key, by using the
Ed25519 identity already on disk at
~/.ollama/id_ed25519(the oneollama signinestablishes) — the keyless, zero-config path, analogous to how the Codex provider
rides a ChatGPT subscription instead of an API key.
Today (after #13) the Ollama provider supports local discovery (no auth) and
Ollama Cloud via
OLLAMA_API_KEY→Authorization: Bearer <key>. This issuetracks the keyless Ed25519 path, to be done correctly and verified.
Why the first attempt was removed in #13
#13 originally shipped a hand-rolled
sources/ollama_auth.pythat did notimplement Ollama's real auth. It pre-signed a self-timestamped string
(
{method},{url}?ts={ts}) and sentAuthorization: <pubkey_b64>:<sig_b64>directly to
/api/tags. That is a different, invented protocol; its testswere self-referential (they asserted the module's own output format, never hit
ollama.com); and failures were swallowed silently (except Exception: return []),so "no error" looked like "it worked". It was never verified against the live
endpoint. Commit
77f8608removed it (and the unpinnedcryptography>=42.0.0dep) and shipped the API-key path; #13 merged as that.
The original code is not lost — recover it from the pre-repair commit:
git show 9eedac2:sources/ollama_auth.py(branch history of #13).The real protocol to implement
Ollama uses a challenge-response that ends in a Bearer token, not a direct
signed header:
WWW-Authenticateheader carryingrealm,service,scope, and a server nonce.method + URL + server-noncewith the Ed25519 key (auth.Sign).(
api.TokenResponse) (getAuthorizationToken).Authorization: Bearer <token>on the actual API request.(Reference: ollama source
auth.Sign/getAuthorizationToken/registryChallenge.)Acceptance criteria (the merge bar)
flow (no client-timestamp scheme, no direct
pubkey:sigheader).401/WWW-Authenticate+ tokenexchange proving it authenticates against
ollama.com(since there is no CI,the test is the load-bearing evidence — self-referential tests don't count).
OLLAMA_CLOUD=1, noOLLAMA_API_KEY, only~/.ollama/id_ed25519→ cloud models actually appear.return []masking a broken handshake).==(the repo pins all deps); justify it (Axis 4).Notes
resource, and the reason this is a follow-up rather than part of feat(ollama): add Ollama provider with Ed25519 OAuth support #13.
half, deferred to its own verified PR.