backend/api/rest/server.go:
- NewServer() now delegates to loadJWTSecret(), which:
- Rejects JWT_SECRET < 32 bytes (log.Fatal).
- Requires JWT_SECRET when APP_ENV=production or GO_ENV=production.
- Generates a 32-byte crypto/rand ephemeral secret in dev only.
- Treats rand.Read failure as fatal (removes the prior time-based
fallback that was deterministic and forgeable).
- Default Content-Security-Policy rewritten:
- Drops 'unsafe-inline' and 'unsafe-eval'.
- Drops private CIDRs (192.168.11.221:854[5|6]).
- Adds frame-ancestors 'none', base-uri 'self', form-action 'self'.
- CSP_HEADER is required in production; fatal if unset there.
backend/api/rest/server_security_test.go (new):
- Covers the three loadJWTSecret() paths (valid, whitespace-trimmed,
ephemeral in dev).
- Covers isProductionEnv() across APP_ENV / GO_ENV combinations.
- Asserts defaultDevCSP contains no unsafe directives or private CIDRs
and includes the frame-ancestors / base-uri / form-action directives.
scripts/*.sh:
- Removed '***REDACTED-LEGACY-PW***' default value from SSH_PASSWORD / NEW_PASSWORD in
7 helper scripts. Each script now fails with exit 2 and points to
docs/SECURITY.md if the password isn't supplied via env or argv.
EXECUTE_DEPLOYMENT.sh, EXECUTE_NOW.sh:
- Replaced hardcoded DB_PASSWORD='***REDACTED-LEGACY-PW***' with a ':?' guard that
aborts with a clear error if DB_PASSWORD (and, for EXECUTE_DEPLOYMENT,
RPC_URL) is not exported. Other env vars keep sensible non-secret
defaults via ${VAR:-default}.
README.md:
- Removed the hardcoded Database Password / RPC URL lines. Replaced with
an env-variable reference table pointing at docs/SECURITY.md and
docs/DATABASE_CONNECTION_GUIDE.md.
docs/DEPLOYMENT.md:
- Replaced 'PASSWORD: SSH password (default: ***REDACTED-LEGACY-PW***)' with a
required-no-default contract and a link to docs/SECURITY.md.
docs/SECURITY.md (new):
- Full secret inventory keyed to the env variable name and the file that
consumes it.
- Five-step rotation checklist covering the Postgres role, the Proxmox
VM SSH password, JWT_SECRET, vendor API keys, and a gitleaks-based
history audit.
- Explicit note that merging secret-scrub PRs does NOT invalidate
already-leaked credentials; rotation is the operator's responsibility.
Verification:
- go build ./... + go vet ./... pass clean.
- Targeted tests (LoadJWTSecret*, IsProduction*, DefaultDevCSP*) pass.
Advances completion criterion 2 (Secrets & config hardened). Residual
leakage from START_HERE.md / LETSENCRYPT_CONFIGURATION_GUIDE.md is
handled by PR #2 (doc consolidation), which deletes those files.
REST API Server
REST API implementation for the ChainID 138 Explorer Platform.
Structure
server.go- Main server setup and route configurationroutes.go- Route handlers and URL parsingauth.go- Wallet auth, user-session auth, RPC product access, subscriptions, and API keysblocks.go- Block-related endpointstransactions.go- Transaction-related endpointsaddresses.go- Address-related endpointssearch.go- Unified search endpointmission_control.go- Mission-control bridge trace and cached liquidity helpersvalidation.go- Input validation utilitiesmiddleware.go- HTTP middleware (logging, compression)errors.go- Error response utilities
API Endpoints
Auth
POST /api/v1/auth/nonce- Create a wallet-signature noncePOST /api/v1/auth/wallet- Authenticate a wallet and receive a track JWTPOST /api/v1/auth/register- Create an access-console user sessionPOST /api/v1/auth/login- Log in to the access console
Blocks
GET /api/v1/blocks- List blocks (paginated)GET /api/v1/blocks/{chain_id}/{number}- Get block by numberGET /api/v1/blocks/{chain_id}/hash/{hash}- Get block by hash
Transactions
GET /api/v1/transactions- List transactions (paginated, filterable)GET /api/v1/transactions/{chain_id}/{hash}- Get transaction by hash
Addresses
GET /api/v1/addresses/{chain_id}/{address}- Get address information
Search
GET /api/v1/search?q={query}- Unified search (auto-detects type: block number, address, or transaction hash)
Health
GET /health- Health check endpoint
Mission control
GET /api/v1/mission-control/stream- SSE stream for bridge/RPC healthGET /api/v1/mission-control/bridge/trace?tx=0x...- Blockscout-backed tx trace with Chain 138 contract labelsGET /api/v1/mission-control/liquidity/token/{address}/pools- 30-second cached proxy to token-aggregation pools
Access and API keys
GET /api/v1/access/me- Current signed-in access user and subscriptionsGET /api/v1/access/products- RPC product catalog for Core, Alltra, and Thirdweb lanesGET /api/v1/access/subscriptions- List product subscriptionsPOST /api/v1/access/subscriptions- Request or activate a product subscriptionGET /api/v1/access/admin/subscriptions- List pending or filtered subscriptions for admin reviewPOST /api/v1/access/admin/subscriptions- Approve, suspend, or revoke a subscription as an adminGET /api/v1/access/api-keys- List issued API keysPOST /api/v1/access/api-keys- Create an API key for a tier, product, scopes, expiry, and optional quota overridePOST /api/v1/access/api-keys/{id}- Revoke an API keyDELETE /api/v1/access/api-keys/{id}- Alternate revoke verbGET /api/v1/access/usage- Per-product usage summaryGET /api/v1/access/audit- Recent validated API-key usage rows for the signed-in userGET /api/v1/access/admin/audit- Admin view of recent validated API-key usage rows, optionally filtered by productPOST /api/v1/access/internal/validate-key- Internal edge validation hook for API-key enforcement and usage loggingGET /api/v1/access/internal/validate-key-auth_request-friendly validator for nginx or similar proxies
Track 4 operator
POST /api/v1/track4/operator/run-script- Run an allowlisted script underOPERATOR_SCRIPTS_ROOT
Features
- Input validation (addresses, hashes, block numbers)
- Pagination support
- Query timeouts for database operations
- CORS headers
- Request logging
- Error handling with consistent error format
- Health checks with database connectivity
- Wallet JWT auth for track endpoints
- Email/password user sessions for the explorer access console
- RPC product catalog, subscription state, API key issuance, revocation, and usage summaries
Running
cd backend/api/rest
go run main.go
Or use the development script:
./scripts/run-dev.sh
Configuration
Set environment variables:
DB_HOST- Database hostDB_PORT- Database portDB_USER- Database userDB_PASSWORD- Database passwordDB_NAME- Database namePORT- API server port (default: 8080)CHAIN_ID- Chain ID (default: 138)RPC_URL- Chain RPC used by Track 1 and mission-control health/SSE dataTOKEN_AGGREGATION_BASE_URL- Upstream token-aggregation base URL for mission-control liquidity proxyBLOCKSCOUT_INTERNAL_URL- Internal Blockscout base URL for bridge trace lookupsEXPLORER_PUBLIC_BASE- Public explorer base URL used in mission-control trace responsesCCIP_RELAY_HEALTH_URL- Optional relay health probe URL, for examplehttp://192.168.11.11:9860/healthzCCIP_RELAY_HEALTH_URLS- Optional comma-separated named relay probes, for examplemainnet=http://192.168.11.11:9860/healthz,bsc=http://192.168.11.11:9861/healthz,avax=http://192.168.11.11:9862/healthzMISSION_CONTROL_CCIP_JSON- Optional JSON snapshot fallback when relay health is provided as a file instead of an HTTP endpointOPERATOR_SCRIPTS_ROOT- Root directory for allowlisted Track 4 scriptsOPERATOR_SCRIPT_ALLOWLIST- Comma-separated list of permitted script names or relative pathsOPERATOR_SCRIPT_TIMEOUT_SEC- Optional Track 4 script timeout in seconds (max 599)JWT_SECRET- Shared secret for wallet and user-session JWT signingACCESS_ADMIN_EMAILS- Comma-separated email allowlist for access-console adminsACCESS_INTERNAL_SECRET- Shared secret used by internal edge validators calling/api/v1/access/internal/validate-key
Auth model
There are now two distinct auth planes:
-
Wallet auth
POST /api/v1/auth/noncePOST /api/v1/auth/wallet- Used for wallet-oriented explorer tracks and operator features.
-
Access-console user auth
POST /api/v1/auth/registerPOST /api/v1/auth/login- Used for
/api/v1/access/*endpoints and the frontend/accessconsole.
RPC access model
The access layer currently models three RPC products:
core-rpc- Provider:
besu-core - VMID:
2101 - Approval required
- Intended for operator-grade and sensitive use
- Provider:
alltra-rpc- Provider:
alltra - VMID:
2102 - Self-service subscription model
- Provider:
thirdweb-rpc- Provider:
thirdweb - VMID:
2103 - Self-service subscription model
- Provider:
The explorer can now:
- register and authenticate users
- publish an RPC product catalog
- create product subscriptions
- issue scoped API keys
- set expiry presets and quota overrides
- rotate keys by minting a replacement and revoking the old one
- review approval-gated subscriptions through an admin surface
- revoke keys
- show usage summaries
- show recent audit activity for users and admins
- validate keys for internal edge enforcement and append usage records
- support nginx
auth_requestintegration through theGET /api/v1/access/internal/validate-keyform
Current limitation:
- the internal validation hook exists, but nginx/Besu/relay still need to call it or replicate its rules to enforce traffic at the edge
- billing collection and invoicing are not yet handled by this package
Operational reference:
explorer-monorepo/deployment/ACCESS_EDGE_ENFORCEMENT_RUNBOOK.mdexplorer-monorepo/deployment/common/nginx-rpc-api-key-gate.conf
Mission-control deployment notes
- Include
explorer-monorepo/deployment/common/nginx-mission-control-sse.confin the same nginx server block that proxies/explorer-api/. - Keep the nginx upstream port aligned with the Go API
PORT. - Verify internal reachability to
BLOCKSCOUT_INTERNAL_URLandTOKEN_AGGREGATION_BASE_URLfrom the API host before enabling the mission-control cards in production.