#!/bin/sh
set -eu
unset YAZA_API_TOKEN_SECONDARY

PROJECT_ROOT=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)
FIXTURE="$PROJECT_ROOT/tests/fixtures/api-route-auth"
JWT_ONLY_FIXTURE="$PROJECT_ROOT/tests/fixtures/api-jwt-only"
TEMP_DIR=$(mktemp -d "${TMPDIR:-/tmp}/yaza-api-route-auth.XXXXXX")
SERVER="$TEMP_DIR/api-server"
JWT_ONLY_SERVER="$TEMP_DIR/jwt-only-server"
PORT=${YAZA_TEST_PORT:-$((25000 + $$ % 30000))}
YAZA_TEST_CLI=${YAZA_TEST_CLI:-yaza}
YAZA_ROUTE_TOKEN='yaza-route-auth-smoke-token-0123456789abcdef'
YAZA_ROUTE_SECONDARY_TOKEN='yaza-route-auth-smoke-token-secondary-9876543210fedcba'
SERVER_PID=
JWT_ONLY_SERVER_PID=

cleanup() {
    if [ -n "$SERVER_PID" ]; then
        kill -TERM "$SERVER_PID" 2>/dev/null || true
        wait "$SERVER_PID" 2>/dev/null || true
    fi
    if [ -n "$JWT_ONLY_SERVER_PID" ]; then
        kill -TERM "$JWT_ONLY_SERVER_PID" 2>/dev/null || true
        wait "$JWT_ONLY_SERVER_PID" 2>/dev/null || true
    fi
    rm -rf "$TEMP_DIR"
}
trap cleanup EXIT HUP INT TERM

fail() {
    printf 'FAIL %s\n' "$1" >&2
    for log_file in "$TEMP_DIR"/*.log; do
        if [ -f "$log_file" ]; then cat "$log_file" >&2; fi
    done
    exit 1
}

build_api() {
    output=$1
    if [ "${YAZA_TEST_SANITIZE:-0}" = 1 ]; then
        "$YAZA_TEST_CLI" build --sanitize src/main.yz -o "$output"
    else
        "$YAZA_TEST_CLI" build src/main.yz -o "$output"
    fi
}

cd "$FIXTURE"
build_api "$SERVER"
"$YAZA_TEST_CLI" generate --openapi -o "$TEMP_DIR/openapi.json"
"$YAZA_TEST_CLI" generate --postman -o "$TEMP_DIR/postman.json"
jq -e '
    .components.securitySchemes.BearerAuth.type == "http"
    and .components.securitySchemes.BearerAuth.scheme == "bearer"
    and .security == [{"BearerAuth": []}, {}]
    and .paths["/api/nested/private"].get.security == [{"BearerAuth": []}]
    and .paths["/api/nested/private"].get["x-yaza-rateLimit"] == {"requests": 7, "windowMs": 60000}
    and .paths["/api/nested/private"].get.responses["202"].description == "Request accepted for processing"
    and .paths["/api/nested/public"].get.security == []
    and .paths["/api/nested/override"].get.security == []
    and .paths["/api/nested/override"].get["x-yaza-rateLimit"] == {"requests": 1, "windowMs": 60000}
    and .paths["/cors"].get["x-yaza-corsOrigin"] == "https://app.example.test"
    and .paths["/cors/nested"].get["x-yaza-corsOrigin"] == "https://app.example.test"
    and .paths["/cors/override"].get["x-yaza-corsOrigin"] == "https://admin.example.test"
    and .paths["/open"].get.security == []
    and .paths["/jwt/private"].get.security == [{"BearerAuth": []}]
    and .paths["/jwt/private"].get["x-yaza-authentication"] == "jwt-hs256"
    and .paths["/jwt/identity"].get.security == [{"BearerAuth": []}]
    and (.paths["/default"].get | has("security") | not)
' "$TEMP_DIR/openapi.json" >/dev/null || fail 'OpenAPI did not preserve route authentication policy'
jq -e '
    any(.variable[]; .key == "apiToken" and .value == "")
    and any(.item[]; .name == "/api/nested/private" and .request.auth.type == "bearer" and .request.auth.bearer[0].value == "{{apiToken}}")
    and (any(.item[]; .name == "/api/nested/public" and (.request | has("auth") | not)))
    and (any(.item[]; .name == "/open" and (.request | has("auth") | not)))
    and any(.item[]; .name == "/jwt/private" and .request.auth.type == "bearer" and .request.auth.bearer[0].value == "{{apiToken}}")
    and any(.item[]; .name == "/jwt/identity" and .request.auth.type == "bearer" and .request.auth.bearer[0].value == "{{apiToken}}")
    and any(.item[]; .name == "/default" and .request.auth.type == "bearer" and .request.auth.bearer[0].value == "{{apiToken}}")
' "$TEMP_DIR/postman.json" >/dev/null || fail 'Postman did not preserve required, public, and inherited bearer policies'

if YAZA_HOST=127.0.0.1 YAZA_PORT="$PORT" DATABASE_URL= "$SERVER" >"$TEMP_DIR/no-token.log" 2>&1; then
    fail 'API unexpectedly started without a token for an auth-required route'
fi
grep -F 'route GET /api/nested/private requires YAZA_API_TOKEN' "$TEMP_DIR/no-token.log" >/dev/null || fail 'missing-token startup failure did not identify the required route safely'

if YAZA_HOST=127.0.0.1 YAZA_PORT="$PORT" YAZA_API_TOKEN= \
    YAZA_API_TOKEN_SECONDARY=$YAZA_ROUTE_SECONDARY_TOKEN DATABASE_URL= \
    "$SERVER" >"$TEMP_DIR/secondary-without-primary.log" 2>&1; then
    fail 'API unexpectedly accepted a secondary token without a primary token'
fi
grep -F 'YAZA_API_TOKEN_SECONDARY requires YAZA_API_TOKEN' \
    "$TEMP_DIR/secondary-without-primary.log" >/dev/null || fail 'secondary-only token configuration was not rejected clearly'
if YAZA_HOST=127.0.0.1 YAZA_PORT="$PORT" YAZA_API_TOKEN="$YAZA_ROUTE_TOKEN" \
    YAZA_API_TOKEN_SECONDARY=smoke-token DATABASE_URL= "$SERVER" \
    >"$TEMP_DIR/secondary-short.log" 2>&1; then
    fail 'API unexpectedly accepted a short secondary Bearer token'
fi
grep -F 'YAZA_API_TOKEN_SECONDARY must be 32..1024 bytes' \
    "$TEMP_DIR/secondary-short.log" >/dev/null || fail 'short secondary token configuration was not rejected clearly'
if YAZA_HOST=127.0.0.1 YAZA_PORT="$PORT" YAZA_API_TOKEN="$YAZA_ROUTE_TOKEN" \
    YAZA_API_TOKEN_SECONDARY="$YAZA_ROUTE_TOKEN" DATABASE_URL= "$SERVER" \
    >"$TEMP_DIR/secondary-duplicate.log" 2>&1; then
    fail 'API unexpectedly accepted duplicate primary and secondary tokens'
fi
grep -F 'YAZA_API_TOKEN_SECONDARY must differ from YAZA_API_TOKEN' \
    "$TEMP_DIR/secondary-duplicate.log" >/dev/null || fail 'duplicate token configuration was not rejected clearly'

if (
    unset YAZA_JWT_SECRET YAZA_JWT_ISSUER YAZA_JWT_AUDIENCE
    YAZA_HOST=127.0.0.1 YAZA_PORT="$PORT" YAZA_API_TOKEN="$YAZA_ROUTE_TOKEN" \
        DATABASE_URL= "$SERVER"
) >"$TEMP_DIR/no-jwt-config.log" 2>&1; then
    fail 'API unexpectedly started without JWT verification configuration'
fi
grep -F 'route GET /jwt/private requires YAZA_JWT_SECRET, YAZA_JWT_ISSUER, and YAZA_JWT_AUDIENCE' \
    "$TEMP_DIR/no-jwt-config.log" >/dev/null || fail 'missing-JWT-config startup failure was unclear'

JWT_SECRET='yaza-auth-smoke-secret-material-0123456789abcdef'
JWT_ISSUER='https://issuer.example.test'
JWT_AUDIENCE='yaza-api-smoke'
encode_base64url() {
    openssl base64 -A | tr '+/' '-_' | tr -d '='
}
make_jwt() {
    header_json=$1
    claims_json=$2
    secret_value=$3
    encoded_header=$(printf '%s' "$header_json" | encode_base64url)
    encoded_claims=$(printf '%s' "$claims_json" | encode_base64url)
    signed_input="$encoded_header.$encoded_claims"
    encoded_signature=$(printf '%s' "$signed_input" | openssl dgst -sha256 -hmac "$secret_value" -binary | encode_base64url)
    printf '%s.%s' "$signed_input" "$encoded_signature"
}
now=$(date +%s)
valid_jwt=$(make_jwt '{"alg":"HS256","typ":"JWT"}' \
    "{\"iss\":\"$JWT_ISSUER\",\"aud\":\"$JWT_AUDIENCE\",\"exp\":$((now + 300)),\"nbf\":$((now - 30)),\"iat\":$((now - 30)),\"sub\":\"user-1\",\"scope\":\"catalog:read\"}" "$JWT_SECRET")
no_subject_jwt=$(make_jwt '{"alg":"HS256","typ":"JWT"}' \
    "{\"iss\":\"$JWT_ISSUER\",\"aud\":\"$JWT_AUDIENCE\",\"exp\":$((now + 300))}" "$JWT_SECRET")
unicode_subject_jwt=$(make_jwt '{"alg":"HS256","typ":"JWT"}' \
    "{\"iss\":\"$JWT_ISSUER\",\"aud\":\"$JWT_AUDIENCE\",\"exp\":$((now + 300)),\"sub\":\"Yahya \\u6771\\ud83d\\ude80\",\"scope\":\"catalog:read\"}" "$JWT_SECRET")
invalid_subject_jwt=$(make_jwt '{"alg":"HS256","typ":"JWT"}' \
    "{\"iss\":\"$JWT_ISSUER\",\"aud\":\"$JWT_AUDIENCE\",\"exp\":$((now + 300)),\"sub\":42}" "$JWT_SECRET")
audience_array_jwt=$(make_jwt '{"alg":"HS256","typ":"JWT"}' \
    "{\"iss\":\"$JWT_ISSUER\",\"aud\":[\"another-api\",\"$JWT_AUDIENCE\"],\"exp\":$((now + 300))}" "$JWT_SECRET")
wrong_audience_array_jwt=$(make_jwt '{"alg":"HS256","typ":"JWT"}' \
    "{\"iss\":\"$JWT_ISSUER\",\"aud\":[\"another-api\",\"wrong-api\"],\"exp\":$((now + 300))}" "$JWT_SECRET")
invalid_audience_array_jwt=$(make_jwt '{"alg":"HS256","typ":"JWT"}' \
    "{\"iss\":\"$JWT_ISSUER\",\"aud\":[\"$JWT_AUDIENCE\",42],\"exp\":$((now + 300))}" "$JWT_SECRET")
expired_jwt=$(make_jwt '{"alg":"HS256","typ":"JWT"}' \
    "{\"iss\":\"$JWT_ISSUER\",\"aud\":\"$JWT_AUDIENCE\",\"exp\":$((now - 30))}" "$JWT_SECRET")
future_jwt=$(make_jwt '{"alg":"HS256","typ":"JWT"}' \
    "{\"iss\":\"$JWT_ISSUER\",\"aud\":\"$JWT_AUDIENCE\",\"exp\":$((now + 300)),\"nbf\":$((now + 120))}" "$JWT_SECRET")
fractional_exp_jwt=$(make_jwt '{"alg":"HS256","typ":"JWT"}' \
    "{\"iss\":\"$JWT_ISSUER\",\"aud\":\"$JWT_AUDIENCE\",\"exp\":$((now + 300)).5}" "$JWT_SECRET")
missing_exp_jwt=$(make_jwt '{"alg":"HS256","typ":"JWT"}' \
    "{\"iss\":\"$JWT_ISSUER\",\"aud\":\"$JWT_AUDIENCE\"}" "$JWT_SECRET")
duplicate_claim_jwt=$(make_jwt '{"alg":"HS256","typ":"JWT"}' \
    "{\"iss\":\"$JWT_ISSUER\",\"aud\":\"$JWT_AUDIENCE\",\"exp\":$((now + 300)),\"exp\":$((now + 600))}" "$JWT_SECRET")
wrong_issuer_jwt=$(make_jwt '{"alg":"HS256","typ":"JWT"}' \
    "{\"iss\":\"https://wrong.example.test\",\"aud\":\"$JWT_AUDIENCE\",\"exp\":$((now + 300))}" "$JWT_SECRET")
wrong_audience_jwt=$(make_jwt '{"alg":"HS256","typ":"JWT"}' \
    "{\"iss\":\"$JWT_ISSUER\",\"aud\":\"another-api\",\"exp\":$((now + 300))}" "$JWT_SECRET")
wrong_algorithm_jwt=$(make_jwt '{"alg":"none","typ":"JWT"}' \
    "{\"iss\":\"$JWT_ISSUER\",\"aud\":\"$JWT_AUDIENCE\",\"exp\":$((now + 300))}" "$JWT_SECRET")
wrong_type_jwt=$(make_jwt '{"alg":"HS256","typ":"refresh+jwt"}' \
    "{\"iss\":\"$JWT_ISSUER\",\"aud\":\"$JWT_AUDIENCE\",\"exp\":$((now + 300))}" "$JWT_SECRET")
tampered_jwt="${valid_jwt%?}x"
padded_jwt="${valid_jwt}="

YAZA_HOST=127.0.0.1 YAZA_PORT="$PORT" YAZA_API_TOKEN="$YAZA_ROUTE_TOKEN" \
    YAZA_API_TOKEN_SECONDARY="$YAZA_ROUTE_SECONDARY_TOKEN" DATABASE_URL= \
    YAZA_JWT_SECRET=$JWT_SECRET YAZA_JWT_ISSUER=$JWT_ISSUER YAZA_JWT_AUDIENCE=$JWT_AUDIENCE \
    "$SERVER" >"$TEMP_DIR/server.log" 2>&1 &
SERVER_PID=$!
attempt=0
until curl -fsS --max-time 1 "http://127.0.0.1:$PORT/healthz" >/dev/null 2>&1; do
    attempt=$((attempt + 1))
    if [ "$attempt" -ge 30 ]; then fail 'route-auth API server did not become ready'; fi
    sleep 0.1
done
grep -F 'shared Bearer token overlap (2 active credentials) + JWT HS256' \
    "$TEMP_DIR/server.log" >/dev/null || fail 'startup did not report that credential overlap is enabled'

request_status() {
    expected=$1
    shift
    actual=$(curl -sS --max-time 5 -D "$TEMP_DIR/response.headers" -o "$TEMP_DIR/response.json" -w '%{http_code}' "$@") || fail 'route middleware request failed'
    [ "$actual" = "$expected" ] || fail "route-auth request returned $actual; expected $expected"
}

request_status 401 "http://127.0.0.1:$PORT/api/nested/private"
request_status 401 -H 'Authorization: Bearer wrong-token' "http://127.0.0.1:$PORT/api/nested/private"
request_status 202 -H "Authorization: Bearer $YAZA_ROUTE_TOKEN" "http://127.0.0.1:$PORT/api/nested/private"
grep -F '{"message":"authenticated"}' "$TEMP_DIR/response.json" >/dev/null || fail 'auth-required route returned the wrong body'
request_status 200 -H "Authorization: Bearer $YAZA_ROUTE_SECONDARY_TOKEN" \
    "http://127.0.0.1:$PORT/default"
grep -F '{"message":"default"}' "$TEMP_DIR/response.json" >/dev/null || fail 'secondary overlap token was not accepted'
request_status 202 -H "Authorization: Bearer $YAZA_ROUTE_TOKEN" \
    -H 'X-Auth-Subject: spoofed-user' "http://127.0.0.1:$PORT/api/nested/identity"
grep -F '{"subject":null,"scope":null}' "$TEMP_DIR/response.json" >/dev/null || fail 'shared bearer auth exposed an unverified identity claim'
request_status 202 "http://127.0.0.1:$PORT/api/nested/public"
grep -F '{"message":"public"}' "$TEMP_DIR/response.json" >/dev/null || fail 'explicitly public route did not bypass the global bearer token'
request_status 202 "http://127.0.0.1:$PORT/open"
grep -F '{"message":"public"}' "$TEMP_DIR/response.json" >/dev/null || fail 'public route group did not bypass the global bearer token'
request_status 202 -H 'X-Auth-Subject: spoofed-user' "http://127.0.0.1:$PORT/open/identity"
grep -F '{"subject":null,"scope":null}' "$TEMP_DIR/response.json" >/dev/null || fail 'public route trusted a spoofed identity header'
request_status 202 -H 'Origin: https://app.example.test' "http://127.0.0.1:$PORT/cors/nested"
grep -F -i 'Access-Control-Allow-Origin: https://app.example.test' "$TEMP_DIR/response.headers" >/dev/null || fail 'nested route did not inherit its group CORS origin'
request_status 202 -H 'Origin: https://untrusted.example.test' "http://127.0.0.1:$PORT/cors/nested"
if grep -F -i 'Access-Control-Allow-Origin:' "$TEMP_DIR/response.headers" >/dev/null; then fail 'unconfigured browser origin received CORS access'; fi
request_status 204 -X OPTIONS -H 'Origin: https://app.example.test' \
    -H 'Access-Control-Request-Method: GET' -H 'Access-Control-Request-Headers: Accept' \
    "http://127.0.0.1:$PORT/cors/nested"
grep -F -i 'Access-Control-Allow-Origin: https://app.example.test' "$TEMP_DIR/response.headers" >/dev/null || fail 'route-scoped CORS preflight omitted its allow-origin header'
grep -F -i 'Access-Control-Allow-Headers: Accept' "$TEMP_DIR/response.headers" >/dev/null || fail 'route-scoped CORS preflight omitted the requested allowed header'
request_status 202 -H 'Origin: https://admin.example.test' "http://127.0.0.1:$PORT/cors/override"
grep -F -i 'Access-Control-Allow-Origin: https://admin.example.test' "$TEMP_DIR/response.headers" >/dev/null || fail 'explicit route CORS policy did not override its group'
request_status 202 -H 'Origin: https://app.example.test' "http://127.0.0.1:$PORT/cors/override"
if grep -F -i 'Access-Control-Allow-Origin:' "$TEMP_DIR/response.headers" >/dev/null; then fail 'overridden group CORS origin was still allowed on the route'; fi
request_status 202 "http://127.0.0.1:$PORT/api/nested/override"
request_status 429 "http://127.0.0.1:$PORT/api/nested/override"
grep -E -i '^Retry-After: [1-9][0-9]*' "$TEMP_DIR/response.headers" >/dev/null || fail 'route-level rate-limit override omitted Retry-After'
request_status 401 "http://127.0.0.1:$PORT/default"
request_status 200 -H "Authorization: Bearer $YAZA_ROUTE_TOKEN" "http://127.0.0.1:$PORT/default"
request_status 202 -H "Authorization: Bearer $YAZA_ROUTE_TOKEN" "http://127.0.0.1:$PORT/api/nested/private"
request_status 401 "http://127.0.0.1:$PORT/jwt/private"
request_status 401 -H "Authorization: Bearer $YAZA_ROUTE_TOKEN" "http://127.0.0.1:$PORT/jwt/private"
request_status 202 -H "Authorization: Bearer $valid_jwt" "http://127.0.0.1:$PORT/jwt/private"
grep -F '{"message":"authenticated"}' "$TEMP_DIR/response.json" >/dev/null || fail 'valid JWT was not accepted'
request_status 202 -H "Authorization: Bearer $audience_array_jwt" "http://127.0.0.1:$PORT/jwt/private"
request_status 401 -H "Authorization: Bearer $wrong_audience_array_jwt" "http://127.0.0.1:$PORT/jwt/private"
request_status 401 -H "Authorization: Bearer $invalid_audience_array_jwt" "http://127.0.0.1:$PORT/jwt/private"
request_status 202 -H "Authorization: Bearer $valid_jwt" "http://127.0.0.1:$PORT/jwt/identity"
grep -F '{"subject":"user-1","scope":"catalog:read"}' "$TEMP_DIR/response.json" >/dev/null || fail 'verified JWT string claims were not available to the handler'
request_status 202 -H "Authorization: Bearer $no_subject_jwt" "http://127.0.0.1:$PORT/jwt/identity"
grep -F '{"subject":null,"scope":null}' "$TEMP_DIR/response.json" >/dev/null || fail 'an absent optional JWT subject did not produce none'
request_status 202 -H "Authorization: Bearer $unicode_subject_jwt" "http://127.0.0.1:$PORT/jwt/identity"
grep -F '{"subject":"Yahya 東🚀","scope":"catalog:read"}' "$TEMP_DIR/response.json" >/dev/null || fail 'JWT Unicode claim escapes were not decoded correctly'
request_status 401 -H "Authorization: Bearer $invalid_subject_jwt" "http://127.0.0.1:$PORT/jwt/identity"
request_status 401 -H "Authorization: Bearer $expired_jwt" "http://127.0.0.1:$PORT/jwt/private"
grep -F '"code":"token_expired"' "$TEMP_DIR/response.json" >/dev/null || fail 'expired JWT did not map to token_expired'
request_status 401 -H "Authorization: Bearer $future_jwt" "http://127.0.0.1:$PORT/jwt/private"
request_status 401 -H "Authorization: Bearer $fractional_exp_jwt" "http://127.0.0.1:$PORT/jwt/private"
request_status 401 -H "Authorization: Bearer $missing_exp_jwt" "http://127.0.0.1:$PORT/jwt/private"
request_status 401 -H "Authorization: Bearer $duplicate_claim_jwt" "http://127.0.0.1:$PORT/jwt/private"
request_status 401 -H "Authorization: Bearer $wrong_issuer_jwt" "http://127.0.0.1:$PORT/jwt/private"
request_status 401 -H "Authorization: Bearer $wrong_audience_jwt" "http://127.0.0.1:$PORT/jwt/private"
request_status 401 -H "Authorization: Bearer $wrong_algorithm_jwt" "http://127.0.0.1:$PORT/jwt/private"
request_status 401 -H "Authorization: Bearer $wrong_type_jwt" "http://127.0.0.1:$PORT/jwt/private"
request_status 401 -H "Authorization: Bearer $tampered_jwt" "http://127.0.0.1:$PORT/jwt/private"
request_status 401 -H "Authorization: Bearer $padded_jwt" "http://127.0.0.1:$PORT/jwt/private"
request_status 202 -H "Authorization: Bearer $valid_jwt" "http://127.0.0.1:$PORT/jwt/also-private"
request_status 202 "http://127.0.0.1:$PORT/api/nested/public"
request_status 429 "http://127.0.0.1:$PORT/api/nested/private"
grep -E -i '^Retry-After: [1-9][0-9]*' "$TEMP_DIR/response.headers" >/dev/null || fail 'route rate-limit response omitted Retry-After'
request_status 202 "http://127.0.0.1:$PORT/open"

cd "$JWT_ONLY_FIXTURE"
build_api "$JWT_ONLY_SERVER"
JWT_ONLY_PORT=$((PORT + 1))
YAZA_HOST=127.0.0.1 YAZA_PORT="$JWT_ONLY_PORT" YAZA_API_TOKEN= DATABASE_URL= \
    YAZA_JWT_SECRET="$JWT_SECRET" YAZA_JWT_ISSUER="$JWT_ISSUER" YAZA_JWT_AUDIENCE="$JWT_AUDIENCE" \
    "$JWT_ONLY_SERVER" >"$TEMP_DIR/jwt-only-server.log" 2>&1 &
JWT_ONLY_SERVER_PID=$!
attempt=0
until curl -fsS --max-time 1 "http://127.0.0.1:$JWT_ONLY_PORT/healthz" >/dev/null 2>&1; do
    attempt=$((attempt + 1))
    if [ "$attempt" -ge 30 ]; then fail 'JWT-only API server did not become ready'; fi
    sleep 0.1
done
actual=$(curl -sS --max-time 5 -o "$TEMP_DIR/jwt-only-response.json" -w '%{http_code}' \
    "http://127.0.0.1:$JWT_ONLY_PORT/private") || fail 'JWT-only unauthenticated request failed'
[ "$actual" = 401 ] || fail "JWT-only unauthenticated request returned $actual; expected 401"
actual=$(curl -sS --max-time 5 -o "$TEMP_DIR/jwt-only-response.json" -w '%{http_code}' \
    -X OPTIONS "http://127.0.0.1:$JWT_ONLY_PORT/private") || fail 'JWT-only unauthenticated OPTIONS request failed'
[ "$actual" = 401 ] || fail "JWT-only unauthenticated OPTIONS request returned $actual; expected 401"
actual=$(curl -sS --max-time 5 -D "$TEMP_DIR/jwt-only-options.headers" \
    -o "$TEMP_DIR/jwt-only-response.json" -w '%{http_code}' -X OPTIONS \
    -H "Authorization: Bearer $valid_jwt" "http://127.0.0.1:$JWT_ONLY_PORT/private") || fail 'JWT-only authenticated OPTIONS request failed'
[ "$actual" = 204 ] || fail "JWT-only authenticated OPTIONS request returned $actual; expected 204"
tr -d '\r' < "$TEMP_DIR/jwt-only-options.headers" | grep -Fx 'Allow: GET, HEAD, OPTIONS' >/dev/null || fail 'JWT-only OPTIONS returned an incorrect Allow header'
[ ! -s "$TEMP_DIR/jwt-only-response.json" ] || fail 'JWT-only OPTIONS returned a response body'
actual=$(curl -sS --max-time 5 -o "$TEMP_DIR/jwt-only-response.json" -w '%{http_code}' \
    -H "Authorization: Bearer $valid_jwt" "http://127.0.0.1:$JWT_ONLY_PORT/private") || fail 'JWT-only authenticated request failed'
[ "$actual" = 202 ] || fail "JWT-only authenticated request returned $actual; expected 202"
grep -F '{"message":"jwt-only"}' "$TEMP_DIR/jwt-only-response.json" >/dev/null || fail 'JWT-only route returned the wrong body'
actual=$(curl -sS --max-time 5 -o "$TEMP_DIR/jwt-only-response.json" -w '%{http_code}' \
    -H "Authorization: Bearer $valid_jwt" "http://127.0.0.1:$JWT_ONLY_PORT/private/identity") || fail 'JWT-only identity request failed'
[ "$actual" = 202 ] || fail "JWT-only identity request returned $actual; expected 202"
grep -F '{"subject":"user-1"}' "$TEMP_DIR/jwt-only-response.json" >/dev/null || fail 'JWT-only route did not expose its verified subject'
actual=$(curl -sS --max-time 5 -o "$TEMP_DIR/jwt-only-response.json" -w '%{http_code}' \
    "http://127.0.0.1:$JWT_ONLY_PORT/open") || fail 'JWT-only public request failed'
[ "$actual" = 200 ] || fail "JWT-only public request returned $actual; expected 200"
grep -F 'JWT HS256 enabled for 2 routes' "$TEMP_DIR/jwt-only-server.log" >/dev/null || fail 'JWT-only startup summary omitted its authentication mode'

printf '%s\n' 'API route middleware smoke passed (shared Bearer and JWT auth, verified claim access, spoof rejection, expiry/issuer/audience/signature rejection, route groups, rate limits, CORS, OpenAPI, and Postman).'
