Stateless LFX v2 Go microservice that manages email alias forwarding via forwardemail.net.
Alias ownership (<alias>@<domain> → LFID) lives in lfx-v2-auth-service as a system-managed Auth0 linked identity. This service only manages the routing (<alias>@<domain> → <target_email>) in forwardemail.net.
lfx-self-serve orchestrates both services.
All subjects are under lfx.forwards-service..
| Subject | Auth | Description |
|---|---|---|
lfx.forwards-service.check_alias |
None | Check whether an alias exists in forwardemail.net. |
lfx.forwards-service.set_target |
JWT | Create or update forwarding routing for the caller's alias. |
lfx.forwards-service.get_forward |
JWT | Read the current forwarding target for the caller's alias. |
All request types require a domain field. Requests missing or sending an empty domain receive a domain_required error.
// request
{"alias": "johndoe", "domain": "linux.com"}
// reply — alias available
{"exists": false, "alias": "johndoe"}
// reply — alias taken
{"exists": true, "alias": "johndoe"}
// reply — invalid alias
{"error": "alias_invalid"}
// reply — domain not in allowed list
{"error": "domain_not_allowed"}// request
{
"user": {"auth_token": "<jwt>"},
"domain": "linux.com",
"target_email": "me@example.com"
}
// reply — success
{"alias": "johndoe", "target_email": "me@example.com", "updated_at": "2026-05-28T00:00:00Z"}
// reply — caller has no identity on this domain
{"error": "not_found"}
// reply — domain not in allowed list
{"error": "domain_not_allowed"}// request
{"user": {"auth_token": "<jwt>"}, "domain": "linux.com"}
// reply — found
{"found": true, "alias": "johndoe", "target_email": "me@example.com"}
// reply — no identity on this domain
{"found": false}
// reply — domain not in allowed list
{"error": "domain_not_allowed"}| Code | Meaning |
|---|---|
alias_invalid |
Alias fails format/length/character validation |
alias_reserved |
Alias is on the reserved-name list |
domain_required |
The domain field was missing or empty |
domain_not_allowed |
Requested domain is not in the service's configured domain list |
unauthorized |
JWT missing, invalid, or auth-service call failed |
not_found |
Caller has no alias identity on the requested domain |
target_email_invalid |
target_email is missing or not a valid email address |
forwardemail_error |
forwardemail.net API call failed |
Full message contracts: pkg/api/forwards.go.
| Variable | Required | Default | Description |
|---|---|---|---|
NATS_URL |
Yes | — | NATS server URL |
NATS_CREDENTIALS_FILE |
No | "" |
NKey credentials file path |
FORWARDEMAIL_API_TOKEN |
Yes | — | forwardemail.net basic-auth API token |
FORWARDEMAIL_BASE_URL |
No | https://api.forwardemail.net |
Override for testing |
FORWARDS_DOMAINS |
Yes | — | Comma-separated allow-list of managed domains. Callers must always send domain explicitly. |
FORWARDS_RESERVED_NAMES |
No | "" |
Comma-separated extra reserved alias names |
AUTH0_DOMAIN |
Yes | — | Auth0 tenant hostname for JWKS fetch (e.g. linuxfoundation-dev.auth0.com) |
AUTH0_AUDIENCE |
Yes | — | Expected JWT audience |
AUTH_SERVICE_SUBJECT |
No | lfx.auth-service.user_emails.read |
NATS subject for auth-service |
AUTH_SERVICE_REQUEST_TIMEOUT |
No | 5s |
Timeout for auth-service NATS calls |
LOG_LEVEL |
No | info |
Logging level (debug, info, warn, error) |
OTEL_* |
No | — | Standard OpenTelemetry environment variables |
- Go 1.25+
- NATS server (or dev cluster via
kubectl port-forward) - A forwardemail.net API token
- Auth0 domain + audience (dev tenant)
make build
NATS_URL=nats://localhost:4222 \
FORWARDEMAIL_API_TOKEN=<your-token> \
AUTH0_DOMAIN=linuxfoundation-dev.auth0.com \
AUTH0_AUDIENCE=https://linuxfoundation-dev.auth0.com/api/v2/ \
FORWARDS_DOMAINS=linux.com,linuxfoundation.org \
./bin/lfx-v2-forwards-service/forwards-service# check_alias — no auth required
nats req lfx.forwards-service.check_alias '{"alias":"johndoe","domain":"linux.com"}'
# set_target — JWT required
nats req lfx.forwards-service.set_target \
'{"user":{"auth_token":"<jwt>"},"domain":"linux.com","target_email":"me@example.com"}'
# get_forward — JWT required
nats req lfx.forwards-service.get_forward \
'{"user":{"auth_token":"<jwt>"},"domain":"linux.com"}'
# missing domain — returns domain_required
nats req lfx.forwards-service.check_alias '{"alias":"johndoe"}'
# reply: {"error":"domain_required"}make testmake lintmake helm-templateslfx-self-serve
│
├── NATS r/r ──► lfx-v2-auth-service (alias ownership in Auth0)
│
└── NATS r/r ──► lfx-v2-forwards-service
│
├── NATS r/r ──► lfx-v2-auth-service (user_emails.read)
│
└── HTTPS ──────► api.forwardemail.net
The service is stateless — no database, no KV store, no JetStream.