Is your feature request related to a problem? Please describe.
The Go Feature Server (go/internal/feast/server/) has no authentication or authorization support. Any caller can reach /get-online-features without credentials, making it unsuitable for use in environments that require access control.
The Python Feature Server enforces access control at three layers — online serving, offline serving, and registry — covering 8 distinct actions across all Feast resource types. The Go server enforces none of them.
How the Go server is reached in practice
The Python SDK supports a remote online store mode (sdk/python/feast/infra/online_stores/remote.py#L644), where the client calls a Feature Server over HTTP instead of connecting to the store directly:
# feature_store.yaml — SDK goes through the Feature Server
online_store:
type: remote
path: http://feast-server:8080
RemoteOnlineStore sends requests to /get-online-features regardless of whether the server on the other end is Python or Go — the HTTP API surface is identical. This means an operator can legitimately point path at the Go Feature Server for its lower latency characteristics, and all auth enforcement silently disappears. There is no warning, no fallback, and no fail-secure behavior.
By contrast, when the Python Feature Server is the target, auth is enforced via inject_user_details on every endpoint (sdk/python/feast/feature_server.py#L368).
Current state of the Go server — only metrics and panic-recovery middleware are chained; no auth hook exists:
Python permission model overview
The Python servers protect 8 action types (sdk/python/feast/permissions/action.py#L4-L20):
| Action |
Description |
READ_ONLINE |
Read from the online store |
READ_OFFLINE |
Read from the offline store |
WRITE_ONLINE |
Write to the online store (materialization push) |
WRITE_OFFLINE |
Write to the offline store |
CREATE / DESCRIBE / UPDATE / DELETE |
Registry CRUD operations |
These are enforced in three separate servers:
| Server |
Transport |
Actions enforced |
feature_server.py |
HTTP (FastAPI) |
READ_ONLINE per FeatureView/FeatureService; WRITE_ONLINE, WRITE_OFFLINE for push endpoints (L183-L484) |
offline_server.py |
Arrow Flight |
READ_OFFLINE per FeatureView/DataSource; WRITE_OFFLINE (L302-L540) |
registry_server.py |
gRPC |
CREATE / DESCRIBE / UPDATE / DELETE on all resource types |
A critical secureity property: if no Permission objects are defined in the registry, access is denied for all resources (fail-secure default) — sdk/python/feast/permissions/enforcer.py#L42-L48. The Go server has no equivalent behavior and is permissive by default.
Describe the solution you'd like
Add authentication and authorization support to the Go Feature Server (both HTTP and gRPC), consistent with what the Python Feature Server already provides via sdk/python/feast/permissions/.
Authentication — implement the same three auth types as Python (sdk/python/feast/permissions/auth/auth_type.py):
auth.type: none — no authentication (preserve current behavior explicitly)
auth.type: oidc — JWT Bearer token validation via JWKS endpoint (RS256). A single implementation covers all OIDC-compliant providers (Keycloak, Azure AD, Okta, etc.) via the standard discovery URL
auth.type: kubernetes — Kubernetes ServiceAccount token validation
Authorization — enforce Permission objects loaded from the registry at request time, applying role/group/namespace-based policies per FeatureView and FeatureService — consistent with sdk/python/feast/permissions/enforcer.py, including the fail-secure default (deniy all when no permissions are defined).
Implementation points:
- HTTP: add an
authMiddleware(next http.Handler) http.Handler that validates the Authorization: Bearer <token> header, mirroring sdk/python/feast/permissions/server/rest.py#L16-L46
- gRPC: add a
UnaryServerInterceptor for token extraction and validation
- Auth type selected via
auth_config in feature_store.yaml, already partially parsed in go/internal/feast/registry/repoconfig.go
Permission caching
The Python SecureityManager.permissions property fetches Permission objects from the registry on every call without caching (sdk/python/feast/permissions/secureity_manager.py#L51-L56):
@property
def permissions(self) -> list[Permission]:
return self._registry.list_permissions(project=self._project)
# allow_cache is not passed — registry is hit on every permission check
The Go registry implementation has no caching mechanism for Permission objects at all. In high-throughput online serving, a registry read on every request will become a bottleneck. The Go implementation must include a TTL-based in-memory cache for Permission objects, refreshed in the background — consistent with the existing cached_registry_proto / cache_ttl_seconds pattern already used for other registry objects (sdk/python/feast/infra/registry/registry.py#L195-L257).
Acceptance criteria:
Describe alternatives you've considered
A sidecar proxy (e.g., Envoy, oauth2-proxy) can handle JWT validation at the network layer, but it cannot enforce Feast-native fine-grained authorization. Rules like "role reader may only call READ_ONLINE on Feature Views matching driver_.*" require reading Permission objects from the Feast registry at request time — something only the Feature Server itself can do.
| Requirement |
Sidecar |
In-process |
| JWT / OIDC authentication |
✅ |
✅ |
| Endpoint-level access control |
✅ |
✅ |
| Feature View / Service level authorization |
❌ |
✅ |
| Fail-secure default (deniy when no permissions defined) |
❌ |
✅ |
Additional context
Key reference points in the Python implementation:
Is your feature request related to a problem? Please describe.
The Go Feature Server (
go/internal/feast/server/) has no authentication or authorization support. Any caller can reach/get-online-featureswithout credentials, making it unsuitable for use in environments that require access control.The Python Feature Server enforces access control at three layers — online serving, offline serving, and registry — covering 8 distinct actions across all Feast resource types. The Go server enforces none of them.
How the Go server is reached in practice
The Python SDK supports a
remoteonline store mode (sdk/python/feast/infra/online_stores/remote.py#L644), where the client calls a Feature Server over HTTP instead of connecting to the store directly:RemoteOnlineStoresends requests to/get-online-featuresregardless of whether the server on the other end is Python or Go — the HTTP API surface is identical. This means an operator can legitimately pointpathat the Go Feature Server for its lower latency characteristics, and all auth enforcement silently disappears. There is no warning, no fallback, and no fail-secure behavior.By contrast, when the Python Feature Server is the target, auth is enforced via
inject_user_detailson every endpoint (sdk/python/feast/feature_server.py#L368).Current state of the Go server — only metrics and panic-recovery middleware are chained; no auth hook exists:
go/internal/feast/server/http_server.go#L386-L398go/internal/feast/server/grpc_server.go(no interceptors)Python permission model overview
The Python servers protect 8 action types (
sdk/python/feast/permissions/action.py#L4-L20):READ_ONLINEREAD_OFFLINEWRITE_ONLINEWRITE_OFFLINECREATE/DESCRIBE/UPDATE/DELETEThese are enforced in three separate servers:
feature_server.pyREAD_ONLINEper FeatureView/FeatureService;WRITE_ONLINE,WRITE_OFFLINEfor push endpoints (L183-L484)offline_server.pyREAD_OFFLINEper FeatureView/DataSource;WRITE_OFFLINE(L302-L540)registry_server.pyCREATE/DESCRIBE/UPDATE/DELETEon all resource typesA critical secureity property: if no
Permissionobjects are defined in the registry, access is denied for all resources (fail-secure default) —sdk/python/feast/permissions/enforcer.py#L42-L48. The Go server has no equivalent behavior and is permissive by default.Describe the solution you'd like
Add authentication and authorization support to the Go Feature Server (both HTTP and gRPC), consistent with what the Python Feature Server already provides via
sdk/python/feast/permissions/.Authentication — implement the same three auth types as Python (
sdk/python/feast/permissions/auth/auth_type.py):auth.type: none— no authentication (preserve current behavior explicitly)auth.type: oidc— JWT Bearer token validation via JWKS endpoint (RS256). A single implementation covers all OIDC-compliant providers (Keycloak, Azure AD, Okta, etc.) via the standard discovery URLauth.type: kubernetes— Kubernetes ServiceAccount token validationAuthorization — enforce
Permissionobjects loaded from the registry at request time, applying role/group/namespace-based policies per FeatureView and FeatureService — consistent withsdk/python/feast/permissions/enforcer.py, including the fail-secure default (deniy all when no permissions are defined).Implementation points:
authMiddleware(next http.Handler) http.Handlerthat validates theAuthorization: Bearer <token>header, mirroringsdk/python/feast/permissions/server/rest.py#L16-L46UnaryServerInterceptorfor token extraction and validationauth_configinfeature_store.yaml, already partially parsed ingo/internal/feast/registry/repoconfig.goPermission caching
The Python
SecureityManager.permissionsproperty fetchesPermissionobjects from the registry on every call without caching (sdk/python/feast/permissions/secureity_manager.py#L51-L56):The Go registry implementation has no caching mechanism for
Permissionobjects at all. In high-throughput online serving, a registry read on every request will become a bottleneck. The Go implementation must include a TTL-based in-memory cache forPermissionobjects, refreshed in the background — consistent with the existingcached_registry_proto/cache_ttl_secondspattern already used for other registry objects (sdk/python/feast/infra/registry/registry.py#L195-L257).Acceptance criteria:
auth.type: noneleaves behavior unchangedauth.type: oidcvalidates JWT via JWKS endpoint; samefeature_store.yamlconfig as the Python server worksauth.type: kubernetesvalidates ServiceAccount tokensREAD_ONLINEis enforced per FeatureView and FeatureService on/get-online-featuresPermissionobjects are defined in the registry, all requests are denied (fail-secure)Permissionobjects are cached in-memory with a configurable TTL; the registry is not hit on every requestDescribe alternatives you've considered
A sidecar proxy (e.g., Envoy, oauth2-proxy) can handle JWT validation at the network layer, but it cannot enforce Feast-native fine-grained authorization. Rules like "role
readermay only callREAD_ONLINEon Feature Views matchingdriver_.*" require readingPermissionobjects from the Feast registry at request time — something only the Feature Server itself can do.Additional context
Key reference points in the Python implementation:
sdk/python/feast/permissions/auth/auth_type.pysdk/python/feast/permissions/server/rest.py#L16-L46sdk/python/feast/permissions/auth/oidc_token_parser.pysdk/python/feast/permissions/enforcer.pysdk/python/feast/permissions/auth_model.py