headroomlabs-ai/headroom · error · ValueError
auth_style must be 'post' or 'basic'
Error message
auth_style must be 'post' or 'basic'
What it means
OAuth2ClientCredentials' `auth_style` parameter controls how credentials are sent to the token endpoint and accepts exactly two values: `'post'` (credentials in the form body, the default) and `'basic'` (HTTP Basic auth header). Any other string raises ValueError at construction.
Source
Thrown at plugins/headroom-oauth2/src/headroom_oauth2/provider.py:62
*,
token_url: str,
client_id: str,
client_secret: str,
scopes=None,
audience: str | None = None,
grant_type: str = "client_credentials",
auth_style: str = "post",
extra_params=None,
skew_seconds: int = 60,
timeout_seconds: float = 30.0,
allow_insecure: bool = False,
):
if not token_url:
raise ValueError("token_url is required")
if not client_id or not client_secret:
raise ValueError("client_id and client_secret are required")
if auth_style not in ("post", "basic"):
raise ValueError("auth_style must be 'post' or 'basic'")
if not allow_insecure and not _https_or_local(token_url):
raise ValueError(
"token_url must be https (loopback http allowed for tests; set "
"allow_insecure=True / HEADROOM_OAUTH2_ALLOW_INSECURE=1 to override)"
)
self.token_url = token_url
self.client_id = client_id
self.client_secret = client_secret
self.scopes = list(scopes or [])
self.audience = audience
self.grant_type = grant_type
self.auth_style = auth_style
self.extra_params = dict(extra_params or {})
self.skew = max(0, int(skew_seconds))
self.timeout = timeout_seconds
self._lock = threading.Lock()
self._token: str | None = None
self._exp = 0.0View on GitHub (pinned to 322425c43b)
Solutions
- Use exactly `post` or `basic` (lowercase): set `HEADROOM_OAUTH2_AUTH_STYLE=basic` or pass `auth_style="basic"`
- Map standards names if your config uses RFC-style values: `client_secret_post` → `post`, `client_secret_basic` → `basic`, normalized at config load
- Check your IdP's docs for which style it requires — most (Azure AD, Auth0, Keycloak) accept `post`; some corporate IdPs require `basic`
Example fix
# before
environment:
- HEADROOM_OAUTH2_AUTH_STYLE=client_secret_basic
# after
environment:
- HEADROOM_OAUTH2_AUTH_STYLE=basic
# mapping helper if config uses RFC names:
STYLE_MAP = {"client_secret_post": "post", "client_secret_basic": "basic"}
auth_style = STYLE_MAP.get(raw_style, raw_style) Defensive patterns
Strategy: type-guard
Validate before calling
VALID_STYLES = {"post", "basic"}
RFC_MAP = {"client_secret_post": "post", "client_secret_basic": "basic"}
def normalize_style(raw: str) -> str:
style = RFC_MAP.get(raw.strip().lower(), raw.strip().lower())
if style not in VALID_STYLES:
raise ValueError(f"auth_style must be one of {sorted(VALID_STYLES)}, got {raw!r}")
return style
provider = OAuth2ClientCredentials(token_url=url, auth_style=normalize_style(cfg["auth_style"]), ...) Type guard
def is_valid_auth_style(style: str) -> bool:
return style in {"post", "basic"} Try / catch
try:
provider = OAuth2ClientCredentials(token_url=url, auth_style=cfg_style, ...)
except ValueError as e:
if "auth_style" in str(e):
provider = OAuth2ClientCredentials(token_url=url, auth_style="post", ...) # IdP default, log it
else:
raise Prevention
- Constrain auth_style in typed config: Literal["post", "basic"]
- Normalize case and RFC-style names at config load
- Check the IdP docs for the required style once, then pin it in config
When it happens
Trigger: Passing `auth_style="header"`, `"basic_auth"`, `"Basic"` (capitalized), or `"bearer"` — commonly from `HEADROOM_OAUTH2_AUTH_STYLE` env config where the deployed value doesn't match the exact lowercase vocabulary.
Common situations: Copying config from another OAuth2 library that uses different style names (`client_secret_post`/`client_secret_basic` per RFC 8418 terminology); case-sensitive values from YAML (`Basic`); guesswork names like `header`/`body` in Helm charts or .env files.
Related errors
- unknown compaction format {resolved_format!r}; expected one
- {key}={raw!r} is not an integer
- token_url is required
- client_id and client_secret are required
- bedrock_eventstream_parse_failed
AI-assisted analysis of headroomlabs-ai/headroom@322425c43b (2026-08-15).
Data as JSON: /api/errors/e8cbc15756ab29c9.
Report an issue: GitHub.