cloudflare/cloudflared · error

response from %s did not contain app token

Error message

response from %s did not contain app token

What it means

exchangeOrgToken posts the organization (Cloudflare Access) token to the app's token endpoint to obtain an app-specific token. If the HTTP exchange succeeds but the response body/headers contain no app token, the function fails with this error naming the request URL. It means Cloudflare accepted the org token but did not grant an application token for that request.

Source

Thrown at token/token.go:582

	resp, err := client.Do(appTokenRequest) // nolint: gosec
	if err != nil {
		return "", errors.Wrap(err, "failed to get app token")
	}
	_ = resp.Body.Close()
	var appToken string
	for _, c := range resp.Cookies() {
		//if Org token revoked on exchange, getTokensFromEdge instead
		validAppToken := c.Name == tokenCookie && time.Now().Before(c.Expires)
		if validAppToken {
			appToken = c.Value
			break
		}
	}

	if len(appToken) > 0 {
		return appToken, nil
	}
	return "", fmt.Errorf("response from %s did not contain app token", resp.Request.URL.String())
}

func GetOrgTokenIfExists(authDomain string) (string, error) {
	path, err := generateOrgTokenFilePathFromURL(authDomain)
	if err != nil {
		return "", err
	}
	token, err := getTokenIfExists(path)
	if err != nil {
		return "", err
	}
	var payload jwtPayload
	err = json.Unmarshal(token.UnsafePayloadWithoutVerification(), &payload)
	if err != nil {
		return "", err
	}

	if payload.isExpired() {

View on GitHub (pinned to 2253eeeb25)

Solutions

  1. Verify your identity/email is listed in the Access application's policy in the Zero Trust dashboard and re-login with `cloudflared access login <url>` to refresh the org token.
  2. Check the app's AUD/audience: delete the stale org token file and re-authenticate against the correct team domain.
  3. If the app requires a service token, provide the CF-Access-Client-Id / CF-Access-Client-Secret headers instead of relying on the browser org token.
  4. Confirm the response from the token endpoint (status + body) with debug logging to see whether Cloudflare returned a policy-denial page.
  5. Recreate or fix the Access application if its audience/policy was recently changed.

Example fix

// before
exported, err := token.GetOrgTokenIfExists(authDomain)
appToken, err := token.getToken(appURL, exported, ...) // response did not contain app token
// after — force a fresh login for the right team domain
os.Remove(orgTokenPath)
orgToken, err := token.GetOrgToken(authDomain)
appToken, err := token.getToken(appURL, orgToken, ...)
Defensive patterns

Strategy: try-catch

Validate before calling

// verify an org token exists and was issued for this team domain before exchanging
orgToken, err := token.GetOrgTokenIfExists(authDomain)
if err != nil || orgToken == "" {
    return errors.New("no valid org token; run cloudflared access login <app-url> first")
}

Try / catch

appToken, err := token.getToken(appURL, orgToken, ...)
if err != nil {
    if strings.Contains(err.Error(), "did not contain app token") {
        // most likely policy denial: force re-login and surface guidance
        return fmt.Errorf("%w — ensure your identity is allowed by the app's Access policy; re-run access login", err)
    }
    return err
}

Prevention

When it happens

Trigger: Calling getToken when the token-exchange response has no app token — the user's Access policy does not include an application rule allowing them in, the org token is for a different team domain/audience than the app, or the app requires additional authentication (e.g. service token headers, mTLS, WAF country rule) that was not supplied.

Common situations: Developer not added to the Access application's policy (or policy recently changed); using an org token cached from a previous login to a different team; accessing an app configured for service-token-only auth while authenticating as a browser user; audience (AUD) mismatch after the app was recreated.

Related errors


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