cloudflare/cloudflared · error

failed to parse auth_domain %q: %w

Error message

failed to parse auth_domain %q: %w

What it means

parseAuthDomain in token/jwks.go normalizes the auth_domain claim from the Cloudflare Access metadata JWT into an https URL used for JWKS fetches and cache paths. The claim is prefixed with "https://" and parsed with url.Parse; if that parse fails (malformed input, control characters, invalid URL syntax) the error is wrapped as "failed to parse auth_domain %q: %w".

Source

Thrown at token/jwks.go:84

	payload, err := jws.Verify(keySet)
	if err != nil {
		return nil, errors.Wrap(err, "failed to verify metadata JWT signature")
	}

	var claims metadataClaims
	if err := json.Unmarshal(payload, &claims); err != nil {
		return nil, errors.Wrap(err, "failed to decode verified metadata JWT claims")
	}
	return &claims, nil
}

// parseAuthDomain extracts the canonical hostname used for JWKS requests and
// cache paths from the auth_domain claim.
func parseAuthDomain(authDomain string) (url.URL, error) {
	parsed, err := url.Parse(httpsScheme + "://" + authDomain)
	if err != nil {
		return url.URL{}, fmt.Errorf("failed to parse auth_domain %q: %w", authDomain, err)
	}
	hostname := strings.ToLower(parsed.Hostname())
	if !strings.HasSuffix(hostname, accessDomainSuffix) {
		return url.URL{}, fmt.Errorf("auth_domain %q does not end with %q", authDomain, accessDomainSuffix)
	}
	return url.URL{Scheme: httpsScheme, Host: hostname}, nil
}

// fetchJWKS fetches the JWKS from the auth domain's certs endpoint over HTTPS.
func fetchJWKS(authDomain url.URL) (*jose.JSONWebKeySet, error) {
	jwksURL := authDomain
	jwksURL.Path = accessCertPath

	client := &http.Client{
		CheckRedirect: func(_ *http.Request, _ []*http.Request) error {
			return http.ErrUseLastResponse
		},
		Timeout: time.Second * 10,

View on GitHub (pinned to 2253eeeb25)

Solutions

  1. Check the auth_domain value being passed: it should be a bare hostname like "myteam.cloudflareaccess.com" — no scheme, path, spaces, or wildcards.
  2. Re-fetch the Access metadata JWT; if it came from a stale/corrupted cache or token, obtain a fresh tunnel token from the Cloudflare dashboard.
  3. Fix the TUNNEL_TOKEN / Access application configuration in the Cloudflare Zero Trust dashboard so the team domain is a valid hostname.
  4. Validate the team domain string before constructing the token/config (reject empty or non-hostname values).

Example fix

// before — full URL pasted as team domain
authDomain := "https://myteam.cloudflareaccess.com/" // url.Parse still succeeds here, but e.g. "my team" fails
// after — bare hostname only
authDomain := "myteam.cloudflareaccess.com"
url, err := parseAuthDomain(authDomain)
Defensive patterns

Strategy: validation

Validate before calling

func validAuthDomainInput(authDomain string) error {
	if authDomain == "" {
		return errors.New("auth_domain is empty")
	}
	if strings.ContainsAny(authDomain, " \t\r\n/") {
		return fmt.Errorf("auth_domain %q must be a bare hostname", authDomain)
	}
	if _, err := url.Parse("https://" + authDomain); err != nil {
		return fmt.Errorf("auth_domain %q is not a valid URL: %w", authDomain, err)
	}
	return nil
}

Type guard

func looksLikeHostname(s string) bool {
	u, err := url.Parse("https://" + s)
	return err == nil && u.Hostname() != "" && !strings.ContainsAny(s, " /\t\n")
}

Try / catch

ad, err := parseAuthDomain(authDomain)
var uerr *url.Error
if err != nil {
	if errors.As(err, &uerr) {
		log.Error().Err(uerr).Str("authDomain", authDomain).Msg("malformed auth_domain claim; re-issue tunnel token")
	}
	return err
}

Prevention

When it happens

Trigger: GetAppInfo / testAuthDomain / metadata decoding pass an auth_domain string whose "https://" + authDomain cannot be parsed by net/url.Parse — e.g. the claim contains spaces, control characters, or malformed percent-encodings, or is empty in a way that produces an invalid URL.

Common situations: A corrupted or tampered metadata JWT yields a bogus auth_domain claim; a misconfigured Access application sets auth_domain to a full URL ("https://team.cloudflareaccess.com") or with a scheme/path embedded oddly; environment variables (TUNNEL_TOKEN-based flows) contain a manually edited team name with whitespace or URL-unsafe characters.

Understand the failure class

Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.

Related errors


AI-assisted analysis of cloudflare/cloudflared@2253eeeb25 (2026-09-06). Data as JSON: /api/errors/4cee407c9c4295ee. Report an issue: GitHub.