Implement AiHint on Your Domain
This guide walks you through creating, signing, and deploying an AiHint file. It uses standard command-line tools (OpenSSL, jq, curl) and is language-agnostic.
Prerequisites
You will need:
- OpenSSL — for key generation and signing
- jq — for JSON manipulation (install jq)
- Access to your web server's
/.well-known/directory
Step 1: Generate RSA Keys
Generate a 4096-bit RSA key pair:
# Generate private key
openssl genrsa -out private_key.pem 4096
# Extract public key
openssl rsa -in private_key.pem -pubout -out public_key.pem
The private key is used to sign your AiHint file. Never share it, commit it to version control, or expose it publicly. Only the public key should be published.
Step 2: Publish Your Public Key
Upload public_key.pem to a publicly accessible HTTPS URL on your domain. For example:
https://example.com/.well-known/aihint-pubkey.pem
This URL will be referenced in your AiHint file so that verifiers can fetch the key.
Step 3: Create the AiHint JSON Document
Create a file called aihint.json with the following structure:
{
"version": "0.1",
"type": "global",
"target": "https://example.com",
"issuer": "https://example.com",
"score": 0.75,
"method": "self-assessment-v1",
"issued_at": "2025-06-15T12:00:00Z",
"expires_at": "2026-06-15T12:00:00Z",
"comment": "Self-signed AiHint for example.com",
"public_key_url": "https://example.com/.well-known/aihint-pubkey.pem"
}
Replace the values with your own:
| Field | What to set |
|---|---|
target | Your domain URL |
issuer | Your domain URL (for self-signed) or the issuer's URL |
score | Your trust score (0.0–1.0) |
method | A string identifying your scoring method |
issued_at | Current UTC timestamp in ISO 8601 |
expires_at | Expiration timestamp (e.g., 1 year from now) |
public_key_url | URL where your public key is hosted |
# Current time in ISO 8601 UTC
date -u +"%Y-%m-%dT%H:%M:%SZ"
# One year from now (macOS)
date -u -v+1y +"%Y-%m-%dT%H:%M:%SZ"
# One year from now (Linux)
date -u -d "+1 year" +"%Y-%m-%dT%H:%M:%SZ"
Step 4: Sign the Document
Sign the document using RSA-SHA256:
# Create the canonical payload (everything except signature)
jq 'del(.signature)' aihint.json > payload.json
# Sign the payload
openssl dgst -sha256 -sign private_key.pem -out signature.bin payload.json
# Encode signature as Base64
base64 -i signature.bin -o signature.b64
# Insert the signature into the document
jq --arg sig "$(cat signature.b64 | tr -d '\n')" '. + {signature: $sig}' aihint.json > aihint-signed.json
# Replace the original file
mv aihint-signed.json aihint.json
Step 5: Validate Your File
Before deploying, verify that your file is correctly structured and the signature is valid:
# Check that all required fields are present
jq 'keys' aihint.json
# Verify the signature
jq 'del(.signature)' aihint.json > payload.json
jq -r '.signature' aihint.json | base64 -d > signature.bin
openssl dgst -sha256 -verify public_key.pem -signature signature.bin payload.json
# Should output: "Verified OK"
Step 6: Deploy
Place the signed aihint.json file at your domain's well-known location:
https://example.com/.well-known/aihint.json
Deployment Examples
Apache — place the file in your document root:
cp aihint.json /var/www/html/.well-known/aihint.json
Nginx — ensure the .well-known directory is served:
location /.well-known/ {
root /var/www/html;
default_type application/json;
}
Static hosting (Netlify, Vercel, etc.) — place the file in your project's public/.well-known/ or static/.well-known/ directory.
Verify Deployment
curl -s https://example.com/.well-known/aihint.json | jq .
You should see your signed AiHint document returned.
Step 7: Key Rotation (Ongoing)
Periodically rotate your signing keys:
- Generate a new key pair
- Publish the new public key at a new URL (or replace the existing one)
- Re-sign your AiHint file with the new private key, updating
public_key_url - Keep the old public key available until all hints signed with it have expired
Complete Script
Here is a complete script that generates keys, creates, signs, and validates an AiHint file:
#!/usr/bin/env bash
set -euo pipefail
DOMAIN="example.com"
SCORE="0.75"
METHOD="self-assessment-v1"
COMMENT="Self-signed AiHint"
PUBKEY_URL="https://${DOMAIN}/.well-known/aihint-pubkey.pem"
ISSUED_AT=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
# macOS: date -u -v+1y; Linux: date -u -d "+1 year"
EXPIRES_AT=$(date -u -v+1y +"%Y-%m-%dT%H:%M:%SZ" 2>/dev/null || date -u -d "+1 year" +"%Y-%m-%dT%H:%M:%SZ")
# Generate keys if they don't exist
if [ ! -f private_key.pem ]; then
openssl genrsa -out private_key.pem 4096
openssl rsa -in private_key.pem -pubout -out public_key.pem
fi
# Create the hint document
jq -n \
--arg target "https://${DOMAIN}" \
--arg issuer "https://${DOMAIN}" \
--arg score "$SCORE" \
--arg method "$METHOD" \
--arg issued "$ISSUED_AT" \
--arg expires "$EXPIRES_AT" \
--arg comment "$COMMENT" \
--arg pubkey "$PUBKEY_URL" \
'{
version: "0.1",
type: "global",
target: $target,
issuer: $issuer,
score: ($score | tonumber),
method: $method,
issued_at: $issued,
expires_at: $expires,
comment: $comment,
public_key_url: $pubkey
}' > aihint.json
# Sign it
openssl dgst -sha256 -sign private_key.pem -out sig.bin aihint.json
SIG=$(base64 -i sig.bin | tr -d '\n')
jq --arg sig "$SIG" '. + {signature: $sig}' aihint.json > aihint-signed.json
mv aihint-signed.json aihint.json
rm -f sig.bin
# Verify
jq 'del(.signature)' aihint.json > payload.json
jq -r '.signature' aihint.json | base64 -d > sig.bin
openssl dgst -sha256 -verify public_key.pem -signature sig.bin payload.json
rm -f payload.json sig.bin
echo "AiHint file created and verified: aihint.json"
Next Steps
- Verify a Hint — How to verify AiHint files you receive
- Protocol Specification — Full field reference
- Signature Algorithm — Detailed signing process