cloudflare/cloudflared · error
missing token in the certificate
Error message
missing token in the certificate
What it means
After decoding all PEM blocks, decodeOriginCert requires both ZoneID and APIToken to have been populated (normally by the ARGO TUNNEL TOKEN block). If either is missing the cert is unusable for tunnel authentication.
Source
Thrown at credentials/origin_cert.go:107
for block != nil {
switch block.Type {
case "PRIVATE KEY", "CERTIFICATE":
// this is for legacy purposes.
case "ARGO TUNNEL TOKEN":
if originCert.ZoneID != "" || originCert.APIToken != "" {
return nil, fmt.Errorf("found multiple tokens in the certificate")
}
// The token is a string,
// Try the newer JSON format
_ = json.Unmarshal(block.Bytes, &originCert)
default:
return nil, fmt.Errorf("unknown block %s in the certificate", block.Type)
}
block, rest = pem.Decode(rest)
}
if originCert.ZoneID == "" || originCert.APIToken == "" {
return nil, fmt.Errorf("missing token in the certificate")
}
return &originCert, nil
}
func readOriginCert(originCertPath string) ([]byte, error) {
originCert, err := os.ReadFile(originCertPath)
if err != nil {
return nil, fmt.Errorf("cannot read %s to load origin certificate", originCertPath)
}
return originCert, nil
}
// FindOriginCert will check to make sure that the certificate exists at the specified file path.
func FindOriginCert(originCertPath string, log *zerolog.Logger) (string, error) {
if originCertPath == "" {
log.Error().Msgf("Cannot determine default origin certificate path. No file %s in %v. You need to specify the origin certificate path by specifying the origincert option in the configuration file, or set TUNNEL_ORIGIN_CERT environment variable", DefaultCredentialFile, config.DefaultConfigSearchDirectories())View on GitHub (pinned to 2253eeeb25)
Solutions
- Re-run 'cloudflared tunnel login' to obtain a complete cert.pem containing the token block
- Verify the ARGO TUNNEL TOKEN block's base64/PEM payload decodes to JSON with zoneID and apiToken keys
- Check for cloudflared version mismatch between the tool that created the cert and the one consuming it
Example fix
// before
_ = json.Unmarshal(block.Bytes, &originCert)
// after (upstream fix suggestion)
if err := json.Unmarshal(block.Bytes, &originCert); err != nil {
return nil, fmt.Errorf("failed to decode ARGO TUNNEL TOKEN: %w", err)
} Defensive patterns
Strategy: validation
Validate before calling
rest := pemBytes
hasToken := false
for {
b, r := pem.Decode(rest)
if b == nil { break }
if b.Type == "ARGO TUNNEL TOKEN" {
var probe map[string]json.RawMessage
if json.Unmarshal(b.Bytes, &probe) == nil && len(probe["zoneID"]) > 0 && len(probe["apiToken"]) > 0 {
hasToken = true
}
}
rest = r
}
if !hasToken { return errors.New("cert lacks a valid ARGO TUNNEL TOKEN block") } Try / catch
cert, err := credentials.DecodeOriginCert(blocks)
if err != nil && strings.Contains(err.Error(), "missing token") {
// trigger 'cloudflared tunnel login' flow
} Prevention
- Always obtain cert.pem via 'cloudflared tunnel login'
- After any cert regeneration, re-run a decode smoke test
- Keep cloudflared versions consistent across cert producers/consumers
When it happens
Trigger: PEM bundle has no 'ARGO TUNNEL TOKEN' block, or the token block's JSON payload lacks zoneID/apiToken fields (empty or wrong-shaped JSON silently unmarshaled).
Common situations: Cert regenerated by newer cloudflared but old tooling expects fields; token block present but JSON malformed (json.Unmarshal error is intentionally ignored); user hand-built the cert.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- pem encoding failed: %v
- cannot decode empty certificate
- found multiple tokens in the certificate
- unknown block %s in the certificate
- parse CA certificate %s
AI-assisted analysis of cloudflare/cloudflared@2253eeeb25 (2026-09-06).
Data as JSON: /api/errors/1f3972e7bbf13052.
Report an issue: GitHub.