Files
Frank cfed6ef7bb docs(gitea): document client token handling; move the token out of remote URLs
New tools/gitea/client-access.md: the credential file (~/.config/secrets/gitea,
0600) behind a global 'store --file' helper, the git 2.56 credential-store trap
(the key=value block shape parses to an empty get; the file must be one
http://user:token@host:port URL per line), the GIT_TERMINAL_PROMPT=0
verification loop, the lfs.locksverify key that silences the URL echo, and the
rotation procedure. Cross-linked from the gitea index and management pages.

Both workstation remotes are now bare URLs; the token lives in one file.
2026-10-09 13:21:34 -07:00

3.5 KiB

type, title, description, tags, verified
type title description tags verified
reference Gitea Client Access Token-based HTTP access from client workstations — the credential store layout, the git 2.56 store-format trap, and the verification loop.
gitea
git
secrets
2026-10-09

Gitea Client Access

Clients (workstations, agent hosts) reach Gitea over plain HTTP on the LAN: http://192.168.0.143:3000/dank/<repo>.git. Authentication is a Gitea HTTP token sent as the password for user dank. SSH is available on :2222 (see architecture); HTTP + token is what the agent hosts use.

The law: the token never enters a URL, a config file, or a shell rc

A remote URL of the shape http://dank:<token>@host/org.git stores the credential in .git/config, which is copied by every clone, printed by git remote -v, and echoed by the LFS lock warning during git push. Keep the URL bare:

http://192.168.0.143:3000/dank/command-center.git

The credential lives in one file, mode 0600, outside every repository:

Item Value
Credential file ~/.config/secrets/gitea (0600, dir 0700)
Helper (global) git config --global credential.helper 'store --file ~/.config/secrets/gitea'
Scope every repo on the host that talks to 192.168.0.143:3000

The git 2.56 store-format trap

git credential fill reads protocol=/host=/username=/password= blocks on stdin, and the man page shows the same shape for ~/.git-credentials. git credential-store (git 2.56.0, verified) does not parse that shape in the file: a key=value block yields a silent empty get, so git falls through to askpass and dies with could not read Username. Write the file as one URL per line:

http://dank:<token>@192.168.0.143:3000

The host line must carry the port (192.168.0.143:3000) — git keys the lookup on protocol + host:port.

Verify the file answers before trusting it, with prompts disabled so a failure is loud rather than a hang:

printf 'protocol=http\nhost=192.168.0.143:3000\n\n' | git credential-store --file ~/.config/secrets/gitea get

Two lines come back (username=, password=). Silence means the format is wrong.

Verification loop

Run every step with GIT_TERMINAL_PROMPT=0; anything that needs the token from a file the helper cannot read fails immediately instead of blocking on a prompt.

GIT_TERMINAL_PROMPT=0 git ls-remote --heads origin main     # read auth
GIT_TERMINAL_PROMPT=0 git push --dry-run origin main        # write auth
git remote get-url origin                                   # no '@' present
grep -rl '<token>' ~/.gitconfig */.git/config               # no plaintext copies

LFS lock warning

git push on a repo with git-lfs prints Locking support detected on remote … info/lfs.locksverify true and echoes the remote URL — one more place a URL-embedded token leaks. Silence it per repo with the bare URL:

git config lfs.http://192.168.0.143:3000/dank/<repo>.git/info/lfs.locksverify true

Rotating the token

Rotate in the Gitea UI (Settings → Applications), then rewrite only the credential file:

umask 077 && printf 'http://dank:%s@192.168.0.143:3000\n' '<new-token>' > ~/.config/secrets/gitea

Nothing else changes: no remote URL, no rc file, no repository. The old token remains valid until it is deleted in the UI, so delete it there as part of the rotation.

See Also