scheduledauth

package
v0.0.0-...-8caed39 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 18, 2026 License: OSL-3.0 Imports: 14 Imported by: 0

Documentation

Overview

Package scheduledauth provides authentication for the /api/scheduled/* endpoints invoked by Cloud Scheduler / Logic Apps. Two modes are supported:

  • oidc: Google-issued OIDC ID tokens (RS256, JWKS-validated). Used by GCP Cloud Run and GKE deployments where Cloud Scheduler signs an OIDC token with a service-account audience. Subject pinning to the scheduler service account email(s) is REQUIRED — the audience alone is not sufficient if other tenants in the same GCP org could mint tokens with the same `aud` value.

  • bearer: shared-secret HMAC-style bearer (constant-time compare). Used by Azure Container Apps + Logic Apps where the workflow pulls the secret from Key Vault at invocation time.

Design context: GitHub PR #161 / issue #159.

Index

Constants

View Source
const (
	EnvAuthMode     = "SCHEDULED_TASK_AUTH_MODE"     // "oidc" | "bearer" | "disabled"
	EnvOIDCIssuer   = "SCHEDULED_TASK_OIDC_ISSUER"   // default GoogleIssuer
	EnvOIDCJWKSURL  = "SCHEDULED_TASK_OIDC_JWKS_URL" // default GoogleJWKSURL
	EnvOIDCAudience = "SCHEDULED_TASK_OIDC_AUDIENCE" // comma-separated
	EnvOIDCSubjects = "SCHEDULED_TASK_OIDC_SUBJECTS" // comma-separated; REQUIRED in oidc mode
	EnvBearerSecret = "SCHEDULED_TASK_SECRET"        // bearer mode only
)

Environment variable names. Centralized so tests and Terraform stay aligned with the Go code.

View Source
const DefaultClockSkew = 60 * time.Second

DefaultClockSkew is the tolerance applied to exp/nbf checks. Matches the leeway most OIDC providers (Microsoft, Auth0) recommend.

View Source
const GoogleIssuer = "https://accounts.google.com"

GoogleIssuer is the canonical OIDC issuer URL for Google-signed ID tokens (Cloud Scheduler, Cloud Functions, etc.).

View Source
const GoogleJWKSURL = "https://www.googleapis.com/oauth2/v3/certs"

GoogleJWKSURL is Google's JWKS endpoint. Used as the default when the caller does not override it via SCHEDULED_TASK_OIDC_JWKS_URL.

Variables

View Source
var ErrConfigInvalid = errors.New("scheduledauth: invalid configuration")

ErrConfigInvalid signals a fatal configuration parse error. Callers are expected to fail-fast on this — the deploy is misconfigured and the scheduled endpoint would silently accept or reject everything.

View Source
var ErrUnauthorized = errors.New("scheduledauth: unauthorized")

ErrUnauthorized is the validation failure returned by Validate. The detailed reason is wrapped via fmt.Errorf so it gets logged but not returned to the client (which only sees 401).

Functions

func IsUnauthorized

func IsUnauthorized(err error) bool

IsUnauthorized reports whether err originated from a Validate failure. Useful for callers that need to distinguish auth failures from config errors.

Types

type Config

type Config struct {
	Mode      Mode
	Issuer    string
	JWKSURL   string
	Bearer    string
	Audiences []string
	Subjects  []string
	Skew      time.Duration
}

Config holds the parsed configuration for a Validator. NewValidator applies defaults and rejects invalid combinations.

func LoadConfig

func LoadConfig(env EnvSource) (Config, error)

LoadConfig parses Config from env. SCHEDULED_TASK_AUTH_MODE MUST be set explicitly to one of "oidc", "bearer", or "disabled" — an unset value returns ErrConfigInvalid so a missed Terraform/Kubernetes env wiring fails server startup instead of silently booting /api/scheduled/* unauthenticated. "disabled" is reserved for an explicit local-dev choice and must be opted into deliberately.

type EnvMap

type EnvMap map[string]string

EnvMap is an EnvSource backed by a map. Useful in tests.

func (EnvMap) Get

func (m EnvMap) Get(key string) string

Get returns the value for key, or "" if absent.

type EnvSource

type EnvSource interface {
	Get(string) string
}

EnvSource is the minimal interface NewFromEnv depends on. The default implementation (envOS) reads from os.Getenv; tests inject a map.

type Mode

type Mode string

Mode is the authentication mode used for scheduled-task requests.

const (
	// ModeOIDC verifies a Google-issued OIDC ID token (RS256 only) on
	// the Authorization header. Subject pinning is required.
	ModeOIDC Mode = "oidc"

	// ModeBearer compares the Authorization header to a shared secret
	// using crypto/subtle.ConstantTimeCompare. Used on Azure where Logic
	// Apps fetch the secret from Key Vault at runtime.
	ModeBearer Mode = "bearer"

	// ModeDisabled disables auth entirely — every request is allowed
	// through. Intended for local development only. The validator logs
	// a WARN at startup and on every request to make this loud.
	ModeDisabled Mode = "disabled"
)

type Validator

type Validator struct {
	// contains filtered or unexported fields
}

Validator authenticates inbound requests against the configured mode.

func New

func New(cfg Config) (*Validator, error)

New builds a Validator from a parsed Config. The caller is responsible for invoking NewFromEnv (or a similar config loader) to populate Config from environment variables.

In oidc mode, the underlying *oidc.RemoteKeySet performs JWKS retrieval lazily on the first request and refreshes on unknown kid (per https://openid.net/specs/openid-connect-core-1_0.html#RotateSigKeys). Single-flight is built in. There is no fixed TTL — refresh-on- unknown-kid is sufficient because providers always sign new tokens with the new kid before retiring the old key.

To pre-warm the cache and surface JWKS endpoint misconfiguration at startup, callers should invoke (*Validator).Warmup. Failure is logged but does not abort startup — Google's CDN sometimes hiccups and we prefer the validator come up with a stale-on-error fetch on the first real request rather than crashloop the container.

func (*Validator) Middleware

func (v *Validator) Middleware(next http.Handler) http.Handler

Middleware wraps next with auth enforcement. On failure, writes a 401 with no body (avoiding any implementation-detail leakage) and logs the reason. Successful requests pass through unmodified.

func (*Validator) Mode

func (v *Validator) Mode() Mode

Mode returns the validator's auth mode. Useful for /health.

func (*Validator) Validate

func (v *Validator) Validate(ctx context.Context, authz string) error

Validate is the unit-testable core. It returns nil iff the Authorization header satisfies the configured mode's requirements.

func (*Validator) Warmup

func (v *Validator) Warmup(ctx context.Context)

Warmup performs a best-effort sanity check on the JWKS endpoint at startup. Failure is non-fatal — it is logged and the validator stays operable; the underlying *oidc.RemoteKeySet retries on the first real request. This avoids crashlooping the container when Google's CDN hiccups, while still surfacing misconfiguration (wrong URL, blocked egress) prominently in the startup logs.

If ctx has no deadline, a 5s fallback is applied — startup must always make forward progress, even if the caller forgot to bound the warmup. Callers that DO want to wait longer are respected.

Implementation note: go-oidc's RemoteKeySet does not expose a public "fetch now" method — it only fetches on demand from VerifySignature (which requires a parseable JWT). We issue an independent HTTP GET to the JWKS URL to keep the warmup probe lightweight and reusable.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL