#!/usr/bin/env bash # AZ-532 — generate a fresh ES256 (prime256v1) JWT signing key for the admin API. # # Usage: # scripts/generate-jwt-key.sh [] [] # # optional; defaults to a timestamped value (kid-YYYYMMDD-HHMMSS). # Kid becomes the filename: /.pem. # optional; defaults to ./secrets/jwt-keys. # # Rotation procedure (per AZ-532 task spec): # 1) Run this script on the admin host with a NEW . The new private key # lands next to the existing one. # 2) Restart admin (or send SIGHUP if hot-reload is wired). JWKS now exposes # both kids; the OLD kid is still active for signing. # 3) Wait verifier-cache TTL (Cache-Control: max-age=3600 → 1 h). # 4) Set JwtConfig__ActiveKid= and restart admin. Admin signs with # the new key; in-flight tokens minted with the old key still verify. # 5) Wait until all old-kid access tokens have expired (TTL = 15 min). # 6) Delete the old PEM and restart admin. JWKS now lists only the new kid. set -euo pipefail kid="${1:-kid-$(date -u +%Y%m%d-%H%M%S)}" out_dir="${2:-secrets/jwt-keys}" mkdir -p "$out_dir" out_file="$out_dir/$kid.pem" if [[ -e "$out_file" ]]; then echo "ERROR: $out_file already exists. Pick a different kid." >&2 exit 1 fi openssl ecparam -name prime256v1 -genkey -noout -out "$out_file" chmod 600 "$out_file" echo "Generated ES256 key at $out_file" echo "Set JwtConfig__ActiveKid=$kid (or the kid you intend to make active) and restart admin."