Component(s)
router
Is your feature request related to a problem? Please describe.
Summary
Allow EDFS @edfs__natsSubscribe (and other @edfs__*Subscribe) subject templates to reference JWT claims — e.g. {{ claims.sub }} or {{ claims.userId }} — in addition to the existing {{ args.* }} syntax.
Problem
A very common subscription pattern is "subscribe to events for the currently authenticated user":
# Current approach — client must pass their own ID as an argument
type Subscription {
messageReceived(myUserId: UUID!): Message!
@edfs__natsSubscribe(
subjects: ["edfs.messages.{{ args.myUserId }}"]
)
}
This forces every client to explicitly provide its own user ID as a subscription argument. In practice, the server already knows who the user is from the JWT token. Exposing this as a required argument creates several issues:
1. Security concern
The argument is untrusted by default. A client could subscribe with someone else's ID. To prevent this, you must write a custom Go module that compares args.myUserId against the JWT claim and rejects mismatches. This is arguably the most common authorization check for per-user subscriptions, yet it requires a custom module to implement:
// custom Go module — runs on every subscription start
if args.MyUserId != claims.Sub {
return errors.New("unauthorized")
}
2. Go knowledge and custom module overhead
Not every team has Go expertise. Writing, compiling, and maintaining a custom router module is a significant barrier for teams using Node.js/TypeScript/Java backends.
Beyond writing the code, maintaining a custom module introduces ongoing friction:
- Building the router — every deployment requires compiling a custom Go binary instead of using the official Docker image
- Version bumps — upgrading the router is no longer just pulling a new image. You must ensure your custom module compiles against the new router version
- CI/CD complexity — the build pipeline needs Go toolchain, module dependencies, and a custom Dockerfile
- Risk of errors — a misconfigured or broken module can silently break subscriptions in production
3. Schema pollution
myUserId is not a meaningful API argument. The client doesn't choose whose messages to receive — it's always their own. The argument exists solely as a workaround for the template engine's limitation.
4. Duplication across subscriptions
Every per-user subscription needs the same boilerplate argument and the same validation in the custom module. In my project, 14 out of 53 subscriptions follow this pattern.
Describe the solution you'd like
Proposed Solution
Support a claims namespace in subject templates, covering both the standard JWT sub claim and custom claims:
type Subscription {
# Using standard JWT "sub" claim
messageReceived: Message!
@authenticated
@edfs__natsSubscribe(
subjects: ["edfs.messages.{{ claims.sub }}"]
)
# Using a custom JWT claim
characterUpdated: Character!
@authenticated
@edfs__natsSubscribe(
subjects: ["edfs.characters.{{ claims.characterId }}"]
)
}
The router already has access to JWT claims via request.auth.claims (used in template expressions for headers and configuration). Extending this to EDFS subject templates would be a natural addition.
Supported template variables
| Template |
Source |
{{ args.myUserId }} |
GraphQL argument (existing) |
{{ claims.sub }} |
Standard JWT sub claim |
{{ claims.<custom> }} |
Any custom JWT claim (e.g. userId, characterId) |
Both {{ claims.sub }} and custom claims like {{ claims.userId }} should be supported, since different teams store user identity in different claims depending on their auth provider setup.
Benefits
- Zero custom modules for the most common auth pattern
- No custom router builds — use the official Docker image as-is, trivial version bumps
- Secure by default — no mismatch between argument and token possible
- Cleaner schema — no dummy arguments that exist solely for routing
- Lower barrier to entry — works out of the box, no Go required
Describe alternatives you've considered
No response
Additional context
Current Workaround
Today I use a custom Go module (RouterMiddlewareHandler) to intercept subscription requests, extract the user ID from JWT claims, and validate it matches the subscription argument.
Component(s)
router
Is your feature request related to a problem? Please describe.
Summary
Allow EDFS
@edfs__natsSubscribe(and other@edfs__*Subscribe) subject templates to reference JWT claims — e.g.{{ claims.sub }}or{{ claims.userId }}— in addition to the existing{{ args.* }}syntax.Problem
A very common subscription pattern is "subscribe to events for the currently authenticated user":
This forces every client to explicitly provide its own user ID as a subscription argument. In practice, the server already knows who the user is from the JWT token. Exposing this as a required argument creates several issues:
1. Security concern
The argument is untrusted by default. A client could subscribe with someone else's ID. To prevent this, you must write a custom Go module that compares
args.myUserIdagainst the JWT claim and rejects mismatches. This is arguably the most common authorization check for per-user subscriptions, yet it requires a custom module to implement:2. Go knowledge and custom module overhead
Not every team has Go expertise. Writing, compiling, and maintaining a custom router module is a significant barrier for teams using Node.js/TypeScript/Java backends.
Beyond writing the code, maintaining a custom module introduces ongoing friction:
3. Schema pollution
myUserIdis not a meaningful API argument. The client doesn't choose whose messages to receive — it's always their own. The argument exists solely as a workaround for the template engine's limitation.4. Duplication across subscriptions
Every per-user subscription needs the same boilerplate argument and the same validation in the custom module. In my project, 14 out of 53 subscriptions follow this pattern.
Describe the solution you'd like
Proposed Solution
Support a
claimsnamespace in subject templates, covering both the standard JWTsubclaim and custom claims:The router already has access to JWT claims via
request.auth.claims(used in template expressions for headers and configuration). Extending this to EDFS subject templates would be a natural addition.Supported template variables
{{ args.myUserId }}{{ claims.sub }}subclaim{{ claims.<custom> }}userId,characterId)Both
{{ claims.sub }}and custom claims like{{ claims.userId }}should be supported, since different teams store user identity in different claims depending on their auth provider setup.Benefits
Describe alternatives you've considered
No response
Additional context
Current Workaround
Today I use a custom Go module (
RouterMiddlewareHandler) to intercept subscription requests, extract the user ID from JWT claims, and validate it matches the subscription argument.