sbn
09/07/2026, 7:00 PMairbytehq/airbyte Terraform provider v1.3.0 against a self-managed Airbyte deployment. Every Airbyte resource fails with:
failed to get token: failed to decode token response:
invalid character '<' looking for beginning of value
This affects declarative source definitions, generic sources, and destinations, so it appears to fail during provider authentication rather than in an individual resource configuration.
Our Buildkite script obtains client credentials from AWS Secrets Manager and tries to retrieve a token from the Airbyte Public API:
bash
DNS_NAME="$ENDPOINT:$PORT"
BEARER_TOKEN=$(curl --request POST \
--url "$DNS_NAME/api/public/v1/applications/token" \
--header 'accept: application/json' \
--header 'Content-Type: application/json' \
--data "{\"client_id\":\"$CLIENT_ID\",\"client_secret\":\"$CLIENT_SECRET\",\"grant_type\":\"client_credentials\"}" \
| jq -r .access_token)
SERVER_URL="http://$DNS_NAME/api/public/v1"
Terraform provider configuration is generated into
secrets.tfvars
; we are tracing the exact provider fields now.
The
< parse error suggests the provider’s token request receives HTML (possibly a redirect, invalid endpoint, proxy/SSO page, wrong HTTP/HTTPS scheme, or unexpected URL path).
What exact provider configuration and endpoint format does airbytehq/airbyte v1.3.0 expect for self-managed Airbyte authentication using client credentials?
Should the provider host/server URL include /api/public/v1, and what token endpoint/path should it use? Are there known issues with NodePort URLs, HTTP vs HTTPS, or Airbyte Public API client credentials that result in an HTML response instead of JSON?kapa.ai
09/07/2026, 7:00 PMinvalid character '<' looking for beginning of value occurs because Terraform is attempting to parse an HTML response (such as a <!DOCTYPE html> 404 page, proxy error, or redirect page) as JSON when requesting an access token.
Provider Configuration & Endpoint Format For the airbytehq/airbyte Terraform provider, the configuration depends on whether you let Terraform fetch the token via OAuth2 Client Credentials or pass a pre-fetched bearer token directly [airbyte Provider].
1. Expected server_url For self-managed Airbyte deployments, the provider documentation specifies that server_url must include the public API path [Terraform provider — Pre-1.0; Getting Started]:
server_url = "http://<host>:<port>/api/public/v1"
(Defaults to https://api.airbyte.com/v1 for Airbyte Cloud if omitted) [airbyte Provider; Getting Started].
2. Using client_id and client_secret (with token_url) The provider schema supports [airbyte Provider]:
• client_id (OAuth2 Client ID)
• client_secret (OAuth2 Client Secret)
• token_url (OAuth2 token endpoint URL)
• server_url (API Base URL)
If you configure client_id and client_secret on self-managed Airbyte, ensure you also explicitly configure token_url [airbyte Provider]. The token endpoint for self-managed Airbyte is [Get an access token]:
provider "airbyte" {
server_url = "http://<host>:<port>/api/public/v1"
token_url = "http://<host>:<port>/api/public/v1/applications/token"
client_id = var.client_id
client_secret = var.client_secret
}
If token_url is omitted, the provider may default to Cloud or construct an incorrect path relative to server_url, hitting an endpoint that serves HTML instead of JSON.
3. Alternative: Using bearer_auth Since your CI pipeline already extracts BEARER_TOKEN via curl, you can bypass the provider's token exchange entirely by passing the bearer token directly to the provider schema [airbyte Provider]:
provider "airbyte" {
server_url = "http://<host>:<port>/api/public/v1"
bearer_auth = var.bearer_token
}
Potential Causes for the HTML (<) Response 1. Missing or Default token_url: When relying on client_id and client_secret, omitting token_url can cause the provider to call an invalid URL or Airbyte Cloud's OAuth endpoint, returning an HTML error page [airbyte Provider].
2. Trailing Slashes or Incorrect Paths: The documentation shows public API endpoints structured under /api/public/v1/applications/token [Get an access token]. Ensure extra trailing slashes or incomplete paths are not causing reverse proxy rewrites or 404 HTML routing.
3. HTTP vs. HTTPS / NodePort & Reverse Proxies: If Airbyte or an ingress controller enforces HTTPS, hitting an http:// endpoint can result in an HTTP 301/302 redirect returning an HTML payload body (<html...) instead of following the redirect to JSON.
Uncertainty and Limitations The knowledge sources do not explicitly mention the internal default value of token_url when targeting a self-hosted server_url, nor do they contain documented issues specifically mentioning Kubernetes NodePort behavior with the v1.3.0 provider. However, explicitly defining token_url or supplying bearer_auth directly avoids the provider's automatic token resolution. 👍 0 button 👎 0 button ℹ️ Tip: Mention @kapa.ai in the thread for follow-ups or DM the app for 1-to-1 help.sbn
09/07/2026, 7:04 PMsbn
09/07/2026, 7:09 PMkapa.ai
09/07/2026, 7:09 PMgrant-type (with a hyphen), not grant_type (with an underscore) [Get an access token]:
{
"client_id": "<YOUR_CLIENT_ID>",
"client_secret": "<YOUR_CLIENT_SECRET>",
"grant-type": "client_credentials"
}
2. Missing Scheme in curl URL Your script sets DNS_NAME="$ENDPOINT:$PORT" and runs:
--url "$DNS_NAME/api/public/v1/applications/token"
Because the scheme (http:// or https://) is omitted, curl or intermediate network proxies may fail to route properly or hit an unexpected endpoint, leading to an HTML response. The scheme should be included [Get an access token].
Corrected Script Updating the scheme and fixing the grant-type parameter:
DNS_NAME="$ENDPOINT:$PORT"
BEARER_TOKEN=$(curl --request POST \
--url "http://$DNS_NAME/api/public/v1/applications/token" \
--header 'accept: application/json' \
--header 'Content-Type: application/json' \
--data "{\"client_id\":\"$CLIENT_ID\",\"client_secret\":\"$CLIENT_SECRET\",\"grant-type\":\"client_credentials\"}" \
| jq -r .access_token)
SERVER_URL="http://$DNS_NAME/api/public/v1"
Will this change suffice for Terraform? I'm sorry, but there's no information about the exact contents of your generated secrets.tfvars or your provider block in the knowledge sources, so whether this change alone will suffice depends on how you configure the provider:
1. If you pass BEARER_TOKEN into Terraform:
If you pass the pre-fetched token into Terraform's bearer_auth attribute, this fix will suffice because the provider will not attempt its own token exchange [airbyte Provider]:provider "airbyte" {
server_url = var.server_url
bearer_auth = var.bearer_token
}
2. If you configure client_id and client_secret in the Terraform provider:
If you rely on Terraform to obtain the token directly rather than passing bearer_auth, the provider itself makes the token request. In that case, you must also provide token_url = "http://$DNS_NAME/api/public/v1/applications/token" in your Terraform provider block; otherwise, the provider may attempt to fetch credentials from a default or cloud token URL [airbyte Provider; Get an access token]. 👍 0 button 👎 0 button ℹ️ Tip: Mention @kapa.ai in the thread for follow-ups or DM the app for 1-to-1 help.sbn
09/07/2026, 7:10 PMkapa.ai
09/07/2026, 7:10 PMfailed to decode token response: invalid character '<' error, you have two primary solutions. The error occurs because an endpoint is returning an HTML page instead of the JSON token response expected by either jq or the Terraform provider.
Solution 1: Use bearer_auth (Recommended if generating tokens in CI/CD) Since your Buildkite script already fetches an access token, pass that token directly to Terraform using the bearer_auth attribute [airbyte Provider]. This bypasses the provider's internal token exchange mechanism entirely.
Step 1: Fix the curl command in your Buildkite script Update the request URL to include the protocol scheme (http:// or https://), and change grant_type to grant-type (hyphenated, as required by the API) [Get an access token]:
DNS_NAME="$ENDPOINT:$PORT"
SERVER_URL="http://$DNS_NAME/api/public/v1"
BEARER_TOKEN=$(curl --request POST \
--url "http://$DNS_NAME/api/public/v1/applications/token" \
--header 'accept: application/json' \
--header 'Content-Type: application/json' \
--data "{\"client_id\":\"$CLIENT_ID\",\"client_secret\":\"$CLIENT_SECRET\",\"grant-type\":\"client_credentials\"}" \
| jq -r .access_token)
Step 2: Pass the token into secrets.tfvars Write the token and server URL to your `secrets.tfvars`:
cat <<EOF > secrets.tfvars
server_url = "$SERVER_URL"
bearer_token = "$BEARER_TOKEN"
EOF
Step 3: Configure the Terraform provider Use bearer_auth in your main.tf [airbyte Provider]:
terraform {
required_providers {
airbyte = {
source = "airbytehq/airbyte"
version = "1.3.0"
}
}
}
provider "airbyte" {
server_url = var.server_url
bearer_auth = var.bearer_token
}
Solution 2: Let Terraform handle token retrieval via client_id, client_secret, and token_url If you want Terraform to handle the OAuth2 token exchange directly, you do not need the curl command in your shell script [Get an access token]. However, on self-managed deployments, you must explicitly provide the token_url so it does not default to Airbyte Cloud [airbyte Provider].
Step 1: Export values to secrets.tfvars Export your base URL, token endpoint URL, and credentials:
DNS_NAME="$ENDPOINT:$PORT"
cat <<EOF > secrets.tfvars
server_url = "http://$DNS_NAME/api/public/v1"
token_url = "http://$DNS_NAME/api/public/v1/applications/token"
client_id = "$CLIENT_ID"
client_secret = "$CLIENT_SECRET"
EOF
Step 2: Configure the Terraform provider Configure the provider schema with token_url, client_id, and client_secret [airbyte Provider]:
terraform {
required_providers {
airbyte = {
source = "airbytehq/airbyte"
version = "1.3.0"
}
}
}
provider "airbyte" {
server_url = var.server_url
token_url = var.token_url
client_id = var.client_id
client_secret = var.client_secret
} 👍 0 button 👎 0 button ℹ️ Tip: Mention @kapa.ai in the thread for follow-ups or DM the app for 1-to-1 help.