Get a card’s public keys from elsewhere as a file
Feed a person’s SSH, minisign and OpenPGP public keys to git, ssh-keygen, a server, minisign or gpg: all of them, or one key by its fingerprint.
/u/{card}/keys.txt- Access
- Public; API key optional
- Client
- Browser fetch supported
Other addresses#
/u/{card}.keys
Parameters#
| Name | Location | Meaning |
|---|---|---|
cardRequired | Path | A person’s permanent card number or its current alias. |
format | Query | allowed_signers for git and ssh-keygen -Y verify, authorized_keys (the default) for a server’s ~/.ssh/authorized_keys, minisign for minisign -V -p, pgp for gpg --import. |
fp | Query | Optional. Keep one key: its fingerprint as ssh-keygen -l, minisign or gpg print it (SHA256:…, the 16-digit minisign key ID, the 40 OpenPGP hex digits), or the public key itself. Write the + of an SSH fingerprint as %2B. |
key | Query | Optional. Another name for fp; give one of the two. |
Request examples#
curl -fsS 'https://veil.rip/u/1/keys.txt?format=allowed_signers' > allowed_signers
git config gpg.ssh.allowedSignersFile "$PWD/allowed_signers"curl -fsS https://veil.rip/u/1.keys >> ~/.ssh/authorized_keyscurl -fsS 'https://veil.rip/u/1/keys.txt?format=pgp' | gpg --importcurl -fsS 'https://veil.rip/u/1/keys.txt?format=allowed_signers&fp=SHA256:yKGK3rJbLA9EAbnKwNXuQvLvsvT0WRrii16h6sF9Rwk' > allowed_signersResponse#
A text file. Comment lines say the card, when the server read it and where each proof is checked; then one line per key in the chosen format. With format=pgp the comments are the Comment lines of one armoured block that holds every OpenPGP key of the card.
Response headers#
| Header | Value | Meaning |
|---|---|---|
Content-Type | text/plain; charset=utf-8 | Use the declared media type before choosing a parser. |
Cache-Control | no-cache | Ask again each time: a removed key leaves the file at once. |
What to verify#
Check each key’s proof on the card before you trust the file for anything that matters: the challenge names the card, the device key and a cosigned checkpoint, and the signature must verify with the key.
Usage notes#
- The file is the server’s word. Each key’s proof of possession is checked in the reader’s browser on the card, or by your client from state.external of the card JSON.
- allowed_signers names each key with the card’s verified email addresses and veil.rip/u/<n>, with no namespace restriction, so commit signatures (namespace git) verify too.
- format=pgp gives an armoured public key block: Comment lines that name the card, the time the server read it and where the proofs are checked, then the card’s OpenPGP keys one after another and the CRC24 line. A card without OpenPGP keys gives the comment lines alone, each starting with #. gpg skips a key without a user ID.
- GET /u/{card}.keys is the same file at the address github.com/<user>.keys made familiar: authorized_keys without parameters, the same format, fp and key, the same headers and errors. An alias never holds a dot, so it is never a card page.
- With fp the file holds that one key, after the same comment lines; the first one names the key. A key the card no longer holds is a 404.
Errors#
API errors return an error object. Use error.code for program logic; error.message is English text for people and can change. Response and error guide
| HTTP | Code | Meaning and next step |
|---|---|---|
| 400 | invalid_parameter | The format is not one of allowed_signers, authorized_keys, minisign or pgp; fp is neither a fingerprint nor a public key; fp and key differ; or the format cannot carry the type of the key fp names (the message names the format that can). Leave format out for authorized_keys or name one of the four, and ask for a key in the format the message names. |
| 404 | not_found | No person card has this number or alias, or the card holds no key with the fingerprint fp names. Check the card, and read its current keys from the card or from the file without fp. |
| 410 | erased | The card existed and was erased or removed. The response also carries its public erasure receipt. Stop using this card as current authority. Retain only the public receipt if needed. |
When using an optional API key
| HTTP | Code | Meaning and next step |
|---|---|---|
| 401 | invalid_api_key | The bearer credential is malformed, unknown, expired or revoked. Use an active key. To use anonymous public access, remove |
| 403 | api_key_scope | The API key lacks read or verify scope, or the endpoint does not accept bearer keys. Use the correct scope. Identity writes and key management still require a device signature. |
| 403 | api_key_suspended | This API key is suspended. Ask staff to restore it; another key cannot lift an account suspension. |
| 403 | developer_suspended | The owner’s API account is suspended or the owner card is unavailable. Check the owner account and any staff restriction. Creating another key does not bypass suspension. |
Shared request errors
| HTTP | Code | Meaning and next step |
|---|---|---|
| 429 | rate_limited | An anonymous, signed-request or API-key allowance was exceeded. Wait at least |
| 500 | internal_error | An unexpected server error occurred. Internal details are not returned. Retry reads with bounded backoff. Check write results before sending a new signed operation. |
| 503 | busy | The application has reached a temporary concurrency or database limit. Wait |