Summary
allowed_jwt_audiences is typed Optional[Sequence[str]], but its mode="before" validator unconditionally calls str2list(v), which assumes v is a string. Passing a list raises AttributeError: 'list' object has no attribute 'replace'.
This only works by accident when the value arrives as a raw env-var string. Any programmatic caller that passes an already-parsed list (e.g. constructing Settings(...) directly, or calling configure_app(allowed_jwt_audiences=[...])) crashes at startup.
Version
Reproduction
from stac_auth_proxy.config import Settings
Settings(
upstream_url="http://localhost:8080",
oidc_discovery_url="https://example/.well-known/openid-configuration",
allowed_jwt_audiences=["sfeos", "account"], # a valid Sequence[str]
)
The validator narrows the accepted input to str | None, contradicting the field's Optional[Sequence[str]] annotation.
Expected behavior
A list/tuple (any Sequence[str]) should pass through unchanged; a comma-separated string should still be split; None/empty should stay None.
Suggested fix
annotate the field with NoDecode so pydantic-settings hands the validator the raw env string (instead of JSON-decoding it first), and make the validator idempotent for list input. This matches how downstreams already work around it:
from pydantic_settings import NoDecode
allowed_jwt_audiences: Annotated[Optional[Sequence[str]], NoDecode] = None
Workaround
Callers can pass a comma-separated string instead of a list, e.g. ",".join(audiences).
Summary
allowed_jwt_audiencesis typedOptional[Sequence[str]], but itsmode="before"validator unconditionally callsstr2list(v), which assumesvis a string. Passing alistraisesAttributeError: 'list' object has no attribute 'replace'.This only works by accident when the value arrives as a raw env-var string. Any programmatic caller that passes an already-parsed list (e.g. constructing
Settings(...)directly, or callingconfigure_app(allowed_jwt_audiences=[...])) crashes at startup.Version
stac-auth-proxy1.1.1Reproduction
The validator narrows the accepted input to
str | None, contradicting the field'sOptional[Sequence[str]]annotation.Expected behavior
A
list/tuple(anySequence[str]) should pass through unchanged; a comma-separated string should still be split;None/empty should stayNone.Suggested fix
annotate the field with
NoDecodeso pydantic-settings hands the validator the raw env string (instead of JSON-decoding it first), and make the validator idempotent for list input. This matches how downstreams already work around it:Workaround
Callers can pass a comma-separated string instead of a list, e.g.
",".join(audiences).