Directives not applied to entity resolvers in Federation mode
Hi, gqlgen team!
We came across an issue with federation generation. Gqlgen does not generate directives on entity resolvers, which creates a security gap when using Apollo Federation.
Problem Description
When using Apollo Federation, directives (like @guard) are correctly applied to query resolvers but are completely bypassed for entity resolvers (_entities query).
This means that authorization checks work for direct queries but being skipped when Apollo Router fetches the same entity through federation's entity resolution mechanism.
Environment
gqlgen version: v0.17.63 Federation version: v2 Go version: 1.24
# schema
directive @guard(name: String, parent: String, skip: String) on OBJECT
type Person @key(fields: "id") @guard(name: "PersonGuard") {
id: String!
email: String!
phone: String!
}
extend type Query {
getPerson(id: String!): Person
}
gqlgen configuration
# gqlgen.yml
federation:
version: 2
generated code for query resolver
// generated/schema.generated.go
func (ec *executionContext) _Query_getPerson(ctx context.Context, field graphql.CollectedField) graphql.Marshaler {
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
directive0 := func(rctx context.Context) (any, error) {
return ec.resolvers.Query().GetPerson(rctx, personID)
}
directive1 := func(ctx context.Context) (any, error) {
name, err := ec.unmarshalOString2ᚖstring(ctx, "PersonGuard")
if err != nil {
return nil, err
}
// ✅ Guard IS applied here
return ec.directives.Guard(ctx, nil, directive0, name, nil, nil)
}
return directive1(rctx)
})
// ...
}
generated code for entity resolver (directivies aren't being applied)
// generated/federation.go
func (ec *executionContext) resolveEntity(
ctx context.Context,
typeName string,
rep EntityRepresentation,
) (e fedruntime.Entity, err error) {
switch typeName {
case "Person":
id, err := ec.unmarshalNString2string(ctx, rep["id"])
if err != nil {
return nil, err
}
// ❌ Guard is NOT applied - direct resolver call
entity, err := ec.resolvers.Entity().FindPersonByID(ctx, id)
if err != nil {
return nil, err
}
return entity, nil
}
}
@ruslanjo Thanks for the reproducible example! This would make a great (currently failing) test case for a PR, and I would really appreciate it if you could contribute that, as well as any further improvements!
@StevenACoffman Thanks for the answer! Just to confirm — would you like me to open a PR that only adds the failing test case for now, or are you expecting a fix as well?
Either! I would appreciate the failing test as a PR, but if you can contribute a fix, that would be even better.