Describe the HTTP request that mints a credential.
This tool never returns a credential. Use it when a job needs a
scoped, short-lived token, or when an S3 client needs a channel's
object-storage key pair.
``purpose="unified"`` (the default) describes ``POST /credentials``,
which mints one ``xh_`` token for git, Postgres, and the platform API.
``purpose="object_storage"`` describes the request for a channel's
S3-compatible key pair, and needs ``app_name`` and ``channel``. Each
result is ``{purpose, method, url, body, returns, console_url}``.
You run the request yourself, so the credential never enters this
conversation.
**Run the request with your own token.** Send the header
``Authorization: Bearer <your token>``, with the token from
``$XHOSTD_TOKEN``. If that variable is unset, ask the user to mint a
token on the console /tokens page and export it as ``XHOSTD_TOKEN``.
Never ask the user to paste a token, and never write a token value
into a command. On a failure, the response body holds the error
envelope ``{"error": {"code", "message"}}``. Without a shell, give the
user ``console_url`` to open in a browser signed in to the console.
Any HTTP client works. For example:
``printf 'Authorization: Bearer %s\n' "$XHOSTD_TOKEN" | curl -sS --fail-with-body --header @- -o <file> <url>``.
The example sends the header on curl's stdin, so the token stays off
the argv of every process, which any local user can read.
The request is a POST, so add ``-X POST``, and ``--json '<body>'``
when ``body`` is not null.
**Two ways to authenticate git and Postgres.** Either one works.
**Use your general token.** ``$XHOSTD_TOKEN`` holds a general token
(``repo:*``, ``db:*``, ``blob:*``, ``snapshots:read``, and more). A
user mints it on the console /tokens page, and a registered agent
receives one at registration. Git over HTTPS and Postgres take it
directly, with no call to this tool. git reads the header from its
environment (git 2.31 or later), so the token stays off its argv,
and the URL-scoped key sends it to the git host alone. Put the
variables in front of every git command that reaches the repo:
``GIT_CONFIG_COUNT=1 GIT_CONFIG_KEY_0=http.https://git.xhostd.com/.extraHeader GIT_CONFIG_VALUE_0="Authorization: Bearer $XHOSTD_TOKEN" git push https://git.xhostd.com/<owner>/<app>.git <branch>``
``PGPASSWORD="$XHOSTD_TOKEN" psql "postgresql://<username>@db.xhostd.com:5432/<db>?sslmode=require"``
**Mint a scoped, short-lived token.** This suits an unattended job,
or a token that you hand to another process. Call
``get_credential_request(scopes=["repo:*"], expires_in=3600)`` for an hour
of git access and nothing else, or ``scopes=["db:*"]`` for Postgres.
Run the request into a variable of its own, so the token stays out of
the command text and out of the output, then use that variable the
same way:
``XHOSTD_GIT_TOKEN="$(printf 'Authorization: Bearer %s\n' "$XHOSTD_TOKEN" | curl -sS --fail-with-body -X POST --header @- --json '{"scopes":["repo:*"],"expires_in":3600}' <url> | python3 -c 'import json,sys; d=json.load(sys.stdin); sys.exit(json.dumps(d)) if "token" not in d else print(d["token"])')" && GIT_CONFIG_COUNT=1 GIT_CONFIG_KEY_0=http.https://git.xhostd.com/.extraHeader GIT_CONFIG_VALUE_0="Authorization: Bearer $XHOSTD_GIT_TOKEN" git push https://git.xhostd.com/<owner>/<app>.git <branch>``
Run the mint and the command that uses the token as one shell
command. A shell variable does not survive into a new shell, and an
agent's tool often starts a new shell for each command. If the mint
fails, python3 prints the error envelope to stderr and exits, so
``&&`` stops before the push. For Postgres, mint with
``{"scopes":["db:*"]}`` into ``XHOSTD_DB_TOKEN`` and chain
``&& PGPASSWORD="$XHOSTD_DB_TOKEN" psql ...`` the same way.
``scopes`` holds a subset of your own capabilities. ``expires_in`` is
in seconds, at most 2592000, and at most what your own token has
left. Without it, the minted token expires in 30 days. A mint never
outlives the token that asked for it. Revoke the credential any time
on the console /tokens page.
**Renew from your SSH key, never from a credential.** Nothing a mint
returns lives longer than the token that asked for it, so
re-minting cannot extend your access. Sign a fresh login message
with ``~/.ssh/xhost_ed25519`` and post it to ``POST /auth/ssh-key``
— that route restarts the 30-day clock. The guide at
https://docs.xhostd.com/guides/register-as-agent shows the request. If
you lose that key and the account holds no verified
email address, nothing renews the account and no operator can
restore it. Keep the key, and as soon as a person gives you an
address, bind it with ``POST /me/email-verifications``, as that
guide shows.
**Git:** git pushes over SSH or over HTTPS. With a shell, push over
SSH: call ``register_ssh_key`` once per machine and account, then
push to ``git@git.xhostd.com:<username>/<app>.git``. That push needs no
token. When the network blocks outbound port 22, or an SSH push
fails, push over HTTPS with the commands in this description. With no
usable SSH key and no ``$XHOSTD_TOKEN``, ``commit_files`` writes the
commit. ``get_app`` returns each app's exact ``repo_url``.
**Postgres:** ``<db>`` is the app name for the ``prod`` channel or
``<channel>-<app>`` otherwise. External database access must be on
in the console (project settings → External database access).
**Object storage:** the request returns ``{endpoint, region,
bucket, access_key_id, secret_access_key}``. Write the response into
a file only you can read:
``mkdir -p ~/.xhostd && (umask 077; printf 'Authorization: Bearer %s\n' "$XHOSTD_TOKEN" | curl -sS --fail-with-body -X POST --header @- -o ~/.xhostd/s3.json <url>)``.
xhostd audit-logs each fetch. A client outside xhostd also needs the console's
external-access toggle on for the bucket. Code that runs in the app
needs no fetch: its runtime already has the ``S3_*`` variables.
Full guide: https://docs.xhostd.com/guides/git.
Reference: https://docs.xhostd.com/mcp-tools#get_credential_request