Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion {{cookiecutter.app_name}}/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,10 @@ make run-docker # Run in Docker container
│ ├── service.go # Business logic: implements gRPC service interface
│ ├── healthcheck.go # Kubernetes liveness/readiness probes
│ ├── service_test.go # Unit tests and benchmarks
│ └── healthcheck_test.go
│ ├── healthcheck_test.go
│ └── auth/
│ ├── auth.go # JWT + API-key auth interceptors (enabled when JWT_SECRET/API_KEYS are set)
│ └── auth_test.go
├── proto/
│ └── *.proto # Protobuf definitions (source of truth for API)
│ └── *.pb.go # GENERATED — do not edit
Expand All @@ -57,6 +60,7 @@ make run-docker # Run in Docker container
- **gRPC-first**: All endpoints are defined in `proto/{{cookiecutter.app_name|lower}}.proto`. HTTP/JSON routes are auto-generated via grpc-gateway annotations. Never create HTTP handlers manually.
- **Context propagation**: `context.Context` is the first parameter everywhere. Interceptors propagate trace IDs, log fields, and options through it.
- **Configuration**: All config via environment variables using `envconfig`. Add fields to `config/config.go` with struct tags. See [ColdBrew config docs](https://pkg.go.dev/github.com/go-coldbrew/core/config#Config) for framework options.
- **Authentication**: JWT and API key auth are built in via `service/auth/`. Config-controlled — set `JWT_SECRET` or `API_KEYS` env vars to enable. Health/ready/reflection RPCs bypass auth automatically. See [Authentication docs](https://docs.coldbrew.cloud/howto/auth/).
- **Health checks**: Kubernetes liveness (`/healthcheck`) and readiness (`/readycheck`) are built-in. Service starts as NOT_SERVING until `SetReady()` is called.
- **Observability**: Prometheus metrics at `/metrics`, pprof at `/debug/pprof/`, OpenAPI/Swagger at `/swagger/`.
- **Graceful shutdown**: ColdBrew handles SIGINT/SIGTERM. The `Stop()` method on your service is called for cleanup.
Expand Down
19 changes: 19 additions & 0 deletions {{cookiecutter.app_name}}/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,25 @@ You can find the environment variables for local development in the `local.env`

A large number of configuration options are powered by [Coldbrew] and used as environment variables. You can find the list of environment variables [here](https://pkg.go.dev/github.com/go-coldbrew/core/config#Config).

## Authentication

JWT and API key authentication are built in and config-controlled. Set environment variables to enable:

```console
$ JWT_SECRET=a-string-secret-at-least-256-bits-long make run # Enable JWT auth
$ API_KEYS=key1,key2,key3 make run # Enable API key auth
```

When enabled, all gRPC RPCs require authentication except health checks, readiness checks, and gRPC reflection. HTTP admin endpoints (`/metrics`, `/debug/pprof/`, `/swagger/`) are not affected by gRPC auth — use `ADMIN_PORT` to isolate them on a separate port. Swagger UI includes an Authorize button for testing.

Generate a test JWT token:

```go
token, _ := auth.GenerateTestToken("a-string-secret-at-least-256-bits-long", "test-user", 1*time.Hour)
```

See [Authentication docs](https://docs.coldbrew.cloud/howto/auth/) for details on claims access, RSA/ECDSA keys, and authorization.

## Logging

This project uses `go-coldbrew/log` to manage logging. You can find documentation [here](https://pkg.go.dev/github.com/go-coldbrew/log).
Expand Down
2 changes: 2 additions & 0 deletions {{cookiecutter.app_name}}/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
cbConfig "github.com/go-coldbrew/core/config"
"github.com/go-coldbrew/log"
"github.com/kelseyhightower/envconfig"
"{{cookiecutter.source_path}}/{{cookiecutter.app_name}}/service/auth"
)

// defaultConfig is the default configuration for the application
Expand All @@ -14,6 +15,7 @@ var defaultConfig Config

type Config struct {
cbConfig.Config
auth.AuthConfig
PanicOnConfigError bool `envconfig:"PANIC_ON_CONFIG_ERROR" default:"true"`
// App configuration
// Remove this line and add your own configuration
Expand Down
27 changes: 20 additions & 7 deletions {{cookiecutter.app_name}}/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,15 @@ require (
buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-20260209202127-80ab13bee0bf.1
github.com/go-coldbrew/core v0.1.45
github.com/go-coldbrew/errors v0.2.13
github.com/go-coldbrew/interceptors v0.1.20
github.com/go-coldbrew/log v0.3.1
github.com/go-coldbrew/options v0.3.0
github.com/golang-jwt/jwt/v5 v5.3.0
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.3
github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0
github.com/kelseyhightower/envconfig v1.4.0
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10
github.com/prometheus/client_golang v1.23.2
github.com/prometheus/client_model v0.6.2
github.com/stretchr/testify v1.11.1
google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9
google.golang.org/grpc v1.80.0
Expand Down Expand Up @@ -61,6 +65,8 @@ require (
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/MirrexOne/unqueryvet v1.5.4 // indirect
github.com/OpenPeeDeeP/depguard/v2 v2.2.1 // indirect
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5 // indirect
github.com/airbrake/gobrake/v5 v5.6.2 // indirect
github.com/alecthomas/chroma/v2 v2.23.1 // indirect
github.com/alecthomas/go-check-sumtype v0.3.1 // indirect
github.com/alexkohler/nakedret/v2 v2.0.6 // indirect
Expand All @@ -85,8 +91,10 @@ require (
github.com/bufbuild/protoplugin v0.0.0-20250218205857-750e09ce93e1 // indirect
github.com/butuzov/ireturn v0.4.0 // indirect
github.com/butuzov/mirror v1.3.0 // indirect
github.com/caio/go-tdigest/v4 v4.0.1 // indirect
github.com/catenacyber/perfsprint v0.10.1 // indirect
github.com/ccojocar/zxcvbn-go v1.0.4 // indirect
github.com/cenkalti/backoff/v5 v5.0.3 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/charithe/durationcheck v0.0.11 // indirect
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect
Expand Down Expand Up @@ -121,13 +129,12 @@ require (
github.com/firefart/nonamedreturns v1.0.6 // indirect
github.com/fsnotify/fsnotify v1.9.0 // indirect
github.com/fzipp/gocyclo v0.6.0 // indirect
github.com/getsentry/sentry-go v0.43.0 // indirect
github.com/ghostiam/protogetter v0.3.20 // indirect
github.com/go-coldbrew/interceptors v0.1.20 // indirect
github.com/go-coldbrew/options v0.2.7 // indirect
github.com/go-coldbrew/hystrixprometheus v0.1.2 // indirect
github.com/go-coldbrew/options v0.3.0 // indirect
github.com/go-coldbrew/tracing v0.2.1 // indirect
github.com/go-critic/go-critic v0.14.3 // indirect
github.com/go-kit/log v0.2.1 // indirect
github.com/go-logfmt/logfmt v0.6.1 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-toolsmith/astcast v1.1.0 // indirect
Expand All @@ -142,6 +149,7 @@ require (
github.com/gobwas/glob v0.2.3 // indirect
github.com/godoc-lint/godoc-lint v0.11.2 // indirect
github.com/gofrs/flock v0.13.0 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/golangci/asciicheck v0.5.0 // indirect
github.com/golangci/dupl v0.0.0-20250308024227-f665c8d69b32 // indirect
github.com/golangci/go-printf-func-name v0.1.1 // indirect
Expand All @@ -162,6 +170,7 @@ require (
github.com/gostaticanalysis/comment v1.5.0 // indirect
github.com/gostaticanalysis/forcetypeassert v0.2.0 // indirect
github.com/gostaticanalysis/nilerr v0.1.2 // indirect
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0 // indirect
github.com/hashicorp/go-immutable-radix/v2 v2.1.0 // indirect
github.com/hashicorp/go-version v1.8.0 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
Expand All @@ -175,6 +184,7 @@ require (
github.com/jingyugao/rowserrcheck v1.1.1 // indirect
github.com/jinzhu/copier v0.4.0 // indirect
github.com/jjti/go-spancheck v0.6.5 // indirect
github.com/jonboulle/clockwork v0.3.0 // indirect
github.com/julz/importas v0.2.0 // indirect
github.com/karamaru-alpha/copyloopvar v1.2.2 // indirect
github.com/kisielk/errcheck v1.10.0 // indirect
Expand Down Expand Up @@ -212,17 +222,18 @@ require (
github.com/muesli/termenv v0.16.0 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/nakabonne/nestif v0.3.1 // indirect
github.com/newrelic/go-agent/v3 v3.42.0 // indirect
github.com/newrelic/go-agent/v3/integrations/nrgrpc v1.4.7 // indirect
github.com/nishanths/exhaustive v0.12.0 // indirect
github.com/nishanths/predeclared v0.2.2 // indirect
github.com/nunnatsa/ginkgolinter v0.23.0 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.1 // indirect
github.com/opentracing/opentracing-go v1.2.0 // indirect
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
github.com/petermattis/goid v0.0.0-20260226131333-17d1149c6ac6 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus/client_golang v1.23.2 // indirect
github.com/prometheus/client_model v0.6.2 // indirect
github.com/prometheus/common v0.67.5 // indirect
github.com/prometheus/procfs v0.20.1 // indirect
github.com/quasilyte/go-ruleguard v0.4.5 // indirect
Expand All @@ -235,6 +246,7 @@ require (
github.com/raeperd/recvcheck v0.2.0 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/rogpeppe/go-internal v1.14.1 // indirect
github.com/rollbar/rollbar-go v1.4.8 // indirect
github.com/rs/cors v1.11.1 // indirect
github.com/rs/zerolog v1.33.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
Expand Down Expand Up @@ -301,6 +313,7 @@ require (
go.opentelemetry.io/otel/sdk v1.43.0 // indirect
go.opentelemetry.io/otel/trace v1.43.0 // indirect
go.opentelemetry.io/proto/otlp v1.10.0 // indirect
go.uber.org/automaxprocs v1.6.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.1 // indirect
go.yaml.in/yaml/v2 v2.4.4 // indirect
Expand Down
7 changes: 7 additions & 0 deletions {{cookiecutter.app_name}}/local.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,10 @@ ENVIRONMENT="dev"
# OpenTelemetry tracing — traces flow to Jaeger when obs profile is running
OTLP_ENDPOINT=localhost:4317
OTLP_INSECURE=true

# Authentication — set either or both to enable (see service/auth/auth.go)
# If both are set, requests can authenticate with either JWT or API key.
# JWT_SECRET=a-string-secret-at-least-256-bits-long
# API_KEYS=key1,key2,key3
# Required for API key auth via HTTP/grpc-gateway (forwards x-api-key header to gRPC metadata)
# HTTP_HEADER_PREFIXES=x-api-key
5 changes: 5 additions & 0 deletions {{cookiecutter.app_name}}/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"{{cookiecutter.source_path}}/{{cookiecutter.app_name}}/config"
{{cookiecutter.app_name|lower}} "{{cookiecutter.source_path}}/{{cookiecutter.app_name}}/proto"
"{{cookiecutter.source_path}}/{{cookiecutter.app_name}}/service"
"{{cookiecutter.source_path}}/{{cookiecutter.app_name}}/service/auth"
"{{cookiecutter.source_path}}/{{cookiecutter.app_name}}/version"
"github.com/go-coldbrew/core"
"github.com/go-coldbrew/log"
Expand Down Expand Up @@ -101,6 +102,10 @@ func main() {
// Set the release name to the git commit hash from the version package
cfg.ReleaseName = version.GitCommit

// Register auth interceptors if JWT_SECRET or API_KEYS env vars are set.
// See service/auth/auth.go and https://docs.coldbrew.cloud/howto/auth/
auth.Setup(context.Background(), config.Get().AuthConfig)

// Initialize the ColdBrew framework with the given configuration
// This is a good place to customise the ColdBrew framework configuration if needed
cb := core.New(cfg)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,38 @@ option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {
}
schemes: HTTP;
schemes: HTTPS;
security_definitions: {
security: {
key: "BearerJWT";
value: {
type: TYPE_API_KEY;
in: IN_HEADER;
name: "Authorization";
description: "JWT Bearer token. Format: \"Bearer {token}\". Set JWT_SECRET env var to enable.";
}
}
security: {
key: "APIKey";
value: {
type: TYPE_API_KEY;
in: IN_HEADER;
name: "x-api-key";
description: "API key authentication. Set API_KEYS env var to enable.";
}
}
}
security: {
security_requirement: {
key: "BearerJWT";
value: {};
}
}
security: {
security_requirement: {
key: "APIKey";
value: {};
}
}
};

message EchoRequest{
Expand All @@ -38,13 +70,19 @@ service {{cookiecutter.service_name}} {
option (google.api.http) = {
get: "/healthcheck"
};
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
security: {}; // No auth required
};
}

//ReadinessProbe for the service
rpc ReadyCheck(google.protobuf.Empty) returns (google.api.HttpBody) {
option (google.api.http) = {
get: "/readycheck"
};
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
security: {}; // No auth required
};
}


Expand Down
Loading
Loading