Production-ready Go server for remote signing of SEP-10 and SEP-45 client domain authentication requests.
This server implements remote signing capabilities for Stellar authentication protocols:
- SEP-10: Web Authentication - Signs transaction envelopes for user authentication
- SEP-45: Web Authentication for Soroban Contracts - Signs authorization entries for contract-based authentication
- SEP-10 transaction signing endpoint
- SEP-45 authorization entries signing endpoint
- Stellar TOML serving
- Bearer token authentication
- CORS support
- Graceful shutdown
- Health check endpoint
- Configuration via JSON file or environment variables
- Go 1.21 or later
Clone the repository and install dependencies:
git clone <repository-url>
cd go-server-signer
go mod downloadThe server can be configured using either a JSON configuration file or environment variables.
Create a config.json file (see config.example.json):
{
"host": "0.0.0.0",
"port": 5003,
"account_id": "GBUTDNISXHXBMZE5I4U5INJTY376S5EW2AF4SQA2SWBXUXJY3OIZQHMV",
"secret": "SBRSOOURG2E24VGDR6NKZJMBOSOHVT6GV7EECUR3ZBE7LGSSVYN5VMOG",
"network_passphrase": "Test SDF Network ; September 2015",
"soroban_rpc_url": "https://soroban-testnet.stellar.org",
"bearer_token": "987654321"
}Alternatively, set these environment variables (see .env.example):
export HOST=0.0.0.0
export PORT=5003
export ACCOUNT_ID=GBUTDNISXHXBMZE5I4U5INJTY376S5EW2AF4SQA2SWBXUXJY3OIZQHMV
export SECRET=SBRSOOURG2E24VGDR6NKZJMBOSOHVT6GV7EECUR3ZBE7LGSSVYN5VMOG
export NETWORK_PASSPHRASE="Test SDF Network ; September 2015"
export SOROBAN_RPC_URL="https://soroban-testnet.stellar.org"
export BEARER_TOKEN=987654321Build the server:
go build -o go-server-signer ./cmd/serverOr use the provided Makefile:
make build./go-server-signer -config config.json./go-server-signergo run ./cmd/server -config config.jsonHealth check endpoint.
Authentication: Not required
Response:
{
"status": "ok"
}Example:
curl http://localhost:5003/healthReturns the Stellar TOML file with the signing key.
Authentication: Not required
Response:
ACCOUNTS = ["GBUTDNISXHXBMZE5I4U5INJTY376S5EW2AF4SQA2SWBXUXJY3OIZQHMV"]
SIGNING_KEY = "GBUTDNISXHXBMZE5I4U5INJTY376S5EW2AF4SQA2SWBXUXJY3OIZQHMV"
NETWORK_PASSPHRASE = "Test SDF Network ; September 2015"Example:
curl http://localhost:5003/.well-known/stellar.tomlSigns a SEP-10 transaction envelope.
Authentication: Required (Bearer token)
Request:
{
"transaction": "<base64 XDR envelope>",
"network_passphrase": "Test SDF Network ; September 2015"
}Response:
{
"transaction": "<signed base64 XDR envelope>",
"network_passphrase": "Test SDF Network ; September 2015"
}Example:
curl -X POST http://localhost:5003/sign-sep-10 \
-H "Authorization: Bearer 987654321" \
-H "Content-Type: application/json" \
-d '{
"transaction": "AAAAAgAAAAD...",
"network_passphrase": "Test SDF Network ; September 2015"
}'Signs a single SEP-45 authorization entry for client domain verification.
Authentication: Required (Bearer token)
Request:
{
"authorization_entry": "<base64 XDR of single SorobanAuthorizationEntry>",
"network_passphrase": "Test SDF Network ; September 2015"
}Response:
{
"authorization_entry": "<signed base64 XDR of single SorobanAuthorizationEntry>",
"network_passphrase": "Test SDF Network ; September 2015"
}Validation: The server validates that the authorization entry's address matches the server's signing key. If it doesn't match, an error is returned:
{
"error": "entry address does not match signing key"
}Example:
curl -X POST http://localhost:5003/sign-sep-45 \
-H "Authorization: Bearer 987654321" \
-H "Content-Type: application/json" \
-d '{
"authorization_entry": "AAAAAgAAAAD...",
"network_passphrase": "Test SDF Network ; September 2015"
}'- Store secrets securely (use environment variables or secure secret management)
- Use HTTPS in production
- Implement rate limiting
- Rotate bearer tokens regularly
- Use strong, randomly generated bearer tokens
- Monitor and log authentication failures
- Consider implementing IP whitelisting
Run the unit tests:
go test ./...Run tests with coverage:
go test -cover ./...Run tests with race detector:
go test -race ./...Or use the Makefile:
make test
make test-coverage
make test-race.
├── cmd/
│ └── server/ # Main application entry point
│ └── main.go
├── internal/
│ ├── config/ # Configuration management
│ │ └── config.go
│ ├── handler/ # HTTP handlers
│ │ ├── handler.go
│ │ └── handler_test.go
│ └── signer/ # Signing logic
│ ├── sep10.go
│ ├── sep10_test.go
│ ├── sep45.go
│ └── sep45_test.go
├── .gitignore
├── .env.example
├── config.example.json
├── Dockerfile
├── docker-compose.yml
├── go.mod
├── go.sum
├── Makefile
└── README.md
All endpoints return appropriate HTTP status codes:
200 OK- Successful operation400 Bad Request- Invalid request parameters or malformed data401 Unauthorized- Missing or invalid authentication405 Method Not Allowed- Wrong HTTP method used500 Internal Server Error- Server error
Error responses include a JSON body with error details:
{
"error": "error message"
}The SEP-45 signing process involves:
- Decoding the base64 XDR of a single
SorobanAuthorizationEntryobject - Validating that the entry's address matches the signer's account ID
- Setting the
signature_expiration_ledgerto current ledger + 10 - Building a
HashIdPreimagewith typeENVELOPE_TYPE_SOROBAN_AUTHORIZATIONcontaining:network_id(SHA256 hash of network passphrase)noncefrom address credentialssignature_expiration_ledger(current ledger + 10)root_invocationfrom the entry
- Computing SHA256 hash of the preimage
- Signing the hash with the keypair
- Setting the signature as an
SCValVec containing a Map withpublic_keyandsignaturebytes - Encoding the signed entry back to base64 XDR
For production deployment:
-
Build the binary with optimizations:
CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -ldflags '-w -s' -o go-server-signer ./cmd/server -
Use a process manager (systemd, supervisor, or Docker)
-
Configure reverse proxy (nginx, caddy) with HTTPS
-
Set up monitoring and logging
-
Implement rate limiting at the reverse proxy level
-
Use secure secret management (HashiCorp Vault, AWS Secrets Manager, etc.)
Build and run with Docker:
docker build -t stellar-remote-signer .
docker run -p 5003:5003 \
-e ACCOUNT_ID=GBUTDNISXHXBMZE5I4U5INJTY376S5EW2AF4SQA2SWBXUXJY3OIZQHMV \
-e SECRET=SBRSOOURG2E24VGDR6NKZJMBOSOHVT6GV7EECUR3ZBE7LGSSVYN5VMOG \
-e BEARER_TOKEN=987654321 \
stellar-remote-signerOr use Docker Compose:
docker-compose upApache 2.0