Production Guides
Auth in Kubernetes
Summary
GoFr supports Basic Auth, API key auth, and OAuth 2.0 JWT validation against a JWKS endpoint (EnableOAuth(jwksEndpoint, refreshInterval, options...)). In Kubernetes, point the JWKS URL at your IdP (cluster-internal Service or public URL), inject API keys via Vault Agent or sealed Secrets, and prefer mTLS or JWT over static keys for service-to-service calls.
What GoFr provides
Three authentication categories are exposed on the App, all verified in pkg/gofr/auth.go — Basic auth, API-key auth, and OAuth/JWT — each with a static-credentials variant and a custom-validator variant:
EnableBasicAuth(credentials...)— pairs of username/password.EnableBasicAuthWithValidator(fn)— custom validator with access to the container.EnableAPIKeyAuth(keys...)—X-Api-Keyheader check.EnableAPIKeyAuthWithValidator(fn)— custom validator.EnableOAuth(jwksEndpoint, refreshIntervalSeconds, options ...jwt.ParserOption)— JWT validation with periodic JWKS refresh.
A single call enables auth on both HTTP and gRPC. The entire /.well-known/* prefix (including /.well-known/alive and /.well-known/health) is auth-exempt by default — see pkg/gofr/http/middleware/validate.go. Re-protect health if you publish it externally.
For full code examples, see Authentication.
OAuth 2.0 with JWKS in Kubernetes
EnableOAuth registers an internal HTTP service named gofr_oauth to fetch keys, then validates JWTs on every request. Two deployment patterns:
Public IdP (Auth0, Okta, Google, Azure AD)
app.EnableOAuth("https://your-tenant.auth0.com/.well-known/jwks.json", 3600,
jwt.WithAudience("https://api.example.com"),
jwt.WithIssuer("https://your-tenant.auth0.com/"),
jwt.WithExpirationRequired())
Egress from your cluster must be allowed to reach the IdP. If you have a strict NetworkPolicy, allowlist the IdP CIDR or use a forward proxy.
Cluster-internal IdP (Keycloak, Dex, Hydra)
If your IdP runs in the same cluster, point at its in-cluster Service DNS:
app.EnableOAuth("http://keycloak.iam.svc.cluster.local:8080/realms/prod/protocol/openid-connect/certs", 3600)
The JWKS fetch is cheap, and the refreshInterval controls how stale your key cache can be. A typical value is 600–3600 seconds. After key rotation by the IdP, requests with old tokens fail until the cache refreshes.
Storing API keys: Vault
EnableAPIKeyAuth takes the keys directly. In production, source them from a secret manager:
- Vault Agent sidecar — mounts a rendered file or sets env vars at pod start, refreshing on a schedule. Inject via the
vault.hashicorp.com/agent-inject: "true"annotation and read withapp.Config.Get. - External Secrets Operator — syncs Vault, AWS Secrets Manager, or GCP Secret Manager into a Kubernetes Secret. Mount as env vars.
- Sealed Secrets — fine for low-rotation keys committed to GitOps repos.
Avoid bundling API keys into ConfigMaps or container images.
Service-to-service auth: pick one model
For internal calls between GoFr services, three reasonable models:
- mTLS via service mesh — Istio
PeerAuthentication: STRICTor Linkerd automatic mTLS. No GoFr code change needed. Strongest identity, requires mesh ops. - JWT — the calling service obtains a token (client credentials or workload identity) and the receiving GoFr service uses
EnableOAuth. Works without a mesh. - Shared API key — simple but rotation-heavy and gives no per-caller identity. Acceptable for low-trust internal endpoints.
Avoid mixing on a single endpoint. Pick one per trust boundary.
Refresh strategy
For OAuth, GoFr refreshes JWKS on the interval you pass. The receiving service does not refresh user tokens — that is the client's responsibility. For long-lived clients (cron jobs, batch workers), refresh ahead of expiry rather than on 401.
Accessing claims in handlers
Once OAuth is enabled, ctx.GetAuthInfo().GetClaims() returns the parsed claim map. Cast specific claims as needed:
claims := ctx.GetAuthInfo().GetClaims()
userID, _ := claims["sub"].(string)
Liveness must stay open
Kubernetes liveness probes fire from the kubelet without credentials. GoFr exempts /.well-known/alive from auth so probes succeed. Do not put auth in front of the alive endpoint via an Ingress filter.
Health endpoint
/.well-known/health is exempted by default but reveals dependency status. In production, re-enable auth on it (or restrict via NetworkPolicy to your monitoring namespace) so it is not enumerable from the public internet.
TLS
Always serve credentials and tokens over TLS. Inside the cluster, the mesh (or CERT_FILE / KEY_FILE configured directly on GoFr) terminates TLS; on the edge, the Ingress does.