ariedeha / xctx
Cross Context - Encrypted, signed, typed context propagation over a single HTTP header.
Installs: 1
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 0
Language:Go
pkg:composer/ariedeha/xctx
Requires
- php: >=8.2
- ext-ctype: *
- ext-curl: *
- ext-openssl: *
- psr/http-message: 1.1
Requires (Dev)
- guzzlehttp/psr7: ^2.6
- phpunit/phpunit: ^10.5
Suggests
- ext-curl: For CurlTransport
- psr/http-message: For PSR-7 request helper in Codec::setHeader/parseFromRequest
This package is auto-updated.
Last update: 2025-10-28 11:14:49 UTC
README
xctx - Cross Context
Encrypted, signed, typed context propagation over a single HTTP header (X-Context) with Go and PHP reference implementations.
- Single header transport (
v1.<base64url(JSON)>) - AEAD (AES‑256‑GCM) with per‑message nonce, versioning, and key IDs (KID) for rotation
- Claims (
iss,aud,iat,nbf,exp,jti) validated on the callee - Typed payload
T(Go generics) / associative array (PHP) — the library is schema‑agnostic - AAD binding for tenant/env binding (non‑secret but must match on both sides)
- Cross‑language interop (Go ↔ PHP) proven in examples
License: Apache‑2.0 (see
LICENSE-APACHE-2.0.txt). Composer package declaresApache-2.0.
Why
Passing many fields across services via body/query/headers is brittle and leaky (and sometimes plain-text). xctx gives you a single, encrypted, signed envelope carrying exactly the system-defined context you want — no more, no less — without the library knowing your field schema.
File Structure
xctx
├── LICENSE-APACHE-2.0.txt
├── README.md
├── clover.xml
├── composer.json
├── composer.lock
├── coverage.out
├── example
│ ├── callee
│ │ ├── go.mod
│ │ ├── main.go
│ │ └── main.php
│ └── caller
│ ├── go.mod
│ ├── main.go
│ └── main.php
├── go.mod
├── phpunit.xml.dist
├── src
│ └── Xctx
│ ├── Codec.php
│ ├── Config.php
│ ├── Exception
│ │ ├── CryptoException.php
│ │ ├── ValidationException.php
│ │ └── XctxException.php
│ ├── Keyring.php
│ └── Util
│ └── Base64Url.php
├── test
│ ├── CodecExceptionBranchesTest.php
│ ├── CodecTest.php
│ ├── ConfigTest.php
│ └── overrides
│ └── crypto_overrides.php
├── xctx.go
├── xctx_blackbox_test.go
├── xctx_config.go
├── xctx_config_blackbox_test.go
├── xctx_config_whitebox_test.go
└── xctx_whitebox_test.go
Quick Start
See USAGE.md for comprehensive instructions. TL;DR:
Go
type PassingContext struct { UserID int32 `json:"user_id"` UserName string `json:"user_name"` Role string `json:"role,omitempty"` } user := xctx.Config{ /* header, issuer, audience, TTL, keys... */ } aad := func() []byte { return []byte("TENANT=blue|ENV=dev") } codec, typedKey, err := xctx.BuildCodecFromEnvWithKey[PassingContext](user, nil, aad) if err != nil { /* handle */ } // Caller: inject typed payload into context and seal ctx := xctx.DefaultInjector[PassingContext](typedKey)(context.Background(), PassingContext{UserID:7, UserName:"arie"}) name, value, _ := codec.EmbedHeaderCtx(ctx) // ("X-Context", "v1.<...>") // Callee: parse from *http.Request newCtx, payload, err := codec.ParseCtx(r)
PHP
use ArieDeha\Xctx\{Config, Codec}; $user = new Config(headerName: 'X-Context', issuer: 'svc-caller', audience: 'svc-callee', ttlSeconds: 120, currentKid: 'kid-demo', currentKey: '0123456789abcdef0123456789abcdef'); $aad = fn() => 'TENANT=blue|ENV=dev'; $codec = Codec::buildFromEnv($user, $aad); // Caller: seal [$name, $value] = $codec->embedHeader(['user_id'=>7,'user_name'=>'arie']); // Callee: parse [$payload, $claims] = $codec->parseHeaderValue($value);
Examples
- Go callee at
:8081and PHP callee at:8082with mutual relays/mutations. - Go and PHP callers demonstrate cross‑language portability and chained updates.
Run order:
# Terminal A go run ./example/callee # Terminal B php -S 127.0.0.1:8082 -t example/callee example/callee/router.php # or: php -S 127.0.0.1:8082 example/callee/main.php # Terminal C go run ./example/caller # Terminal D php example/caller/main.php
Envelope
X-Context: v1.<base64url(json)> where json has lowercase keys:
{ "v":1, "alg":"AES256-GCM", "kid":"kid-demo", "n":"...", "ct":"..." }
Both implementations accept AES256-GCM/AES-256-GCM and lowercase/uppercase keys on parse. Emit is canonicalized to lowercase keys for interop with Go.
Configuration
See USAGE.md for environment variables, key formats (raw/hex/base64), and AAD binding guidance.
Development
- See DEVELOPERS.md for building, testing, and coverage (Go & PHP).
- Security notes: short TTLs, rotation with
OtherKeys, replay mitigation withjti, strict claim checks.