kubernetes/kops · error

decoding authorization token: %w

Error message

decoding authorization token: %w

What it means

VerifyToken expects the incoming authorization token to be a base64-encoded gcetpm.AuthToken JSON prefixed with GCETPMAuthenticationTokenPrefix. If base64.StdEncoding.DecodeString fails on the prefix-stripped value, the token is malformed and cannot even be parsed. This is a client-supplied data validation failure.

Source

Thrown at upup/pkg/fi/cloudup/gce/tpm/gcetpmverifier/tpmverifier.go:85

		computeClient: computeClient,
		capiManager:   capiManager,
	}, nil
}

var _ bootstrap.Verifier = (*tpmVerifier)(nil)

func (v *tpmVerifier) VerifyToken(ctx context.Context, rawRequest *http.Request, authToken string, body []byte) (*bootstrap.VerifyResult, error) {
	// Reminder: we shouldn't trust any data we get from the client until we've checked the signature (and even then...)
	// Thankfully the GCE SDK does seem to escape the parameters correctly, for example.

	if !strings.HasPrefix(authToken, gcetpm.GCETPMAuthenticationTokenPrefix) {
		return nil, bootstrap.ErrNotThisVerifier
	}
	authToken = strings.TrimPrefix(authToken, gcetpm.GCETPMAuthenticationTokenPrefix)

	tokenBytes, err := base64.StdEncoding.DecodeString(authToken)
	if err != nil {
		return nil, fmt.Errorf("decoding authorization token: %w", err)
	}

	token := &gcetpm.AuthToken{}
	if err = json.Unmarshal(tokenBytes, token); err != nil {
		return nil, fmt.Errorf("unmarshalling authorization token: %w", err)
	}

	tokenData := gcetpm.AuthTokenData{}
	if err := json.Unmarshal(token.Data, &tokenData); err != nil {
		return nil, fmt.Errorf("unmarshalling authorization token data: %w", err)
	}

	// Guard against replay attacks
	if tokenData.Audience != gcetpm.AudienceNodeAuthentication {
		return nil, fmt.Errorf("incorrect Audience")
	}
	timeSkew := math.Abs(time.Since(time.Unix(tokenData.Timestamp, 0)).Seconds())
	if timeSkew > float64(v.opt.MaxTimeSkew) {

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Regenerate the token with the matching kops/gcetpm version on the node
  2. Verify both signer and verifier use the same GCETPMAuthenticationTokenPrefix and encoding
  3. Ensure the full token string reaches the verifier (no truncation by proxies/headers)
  4. Check that the client uses base64.StdEncoding (not RawURLEncoding) when constructing the token
  5. Confirm the client is actually the TPM authenticator and not sending a different credential type
Defensive patterns

Strategy: validation

Validate before calling

authHeader := r.Header.Get("Authorization")
if !strings.HasPrefix(authHeader, gcetpm.GCETPMAuthenticationTokenPrefix) {
    return bootstrap.ErrNotThisVerifier
}
b64 := strings.TrimPrefix(authHeader, gcetpm.GCETPMAuthenticationTokenPrefix)
if _, err := base64.StdEncoding.DecodeString(b64); err != nil {
    return fmt.Errorf("client sent non-base64 token")
}

Type guard

func isValidTPMToken(header string) bool {
    if !strings.HasPrefix(header, gcetpm.GCETPMAuthenticationTokenPrefix) {
        return false
    }
    _, err := base64.StdEncoding.DecodeString(strings.TrimPrefix(header, gcetpm.GCETPMAuthenticationTokenPrefix))
    return err == nil
}

Try / catch

token, err := verifier.VerifyToken(ctx, rawToken, request)
if err != nil {
    if strings.Contains(err.Error(), "decoding authorization token") {
        return fmt.Errorf("malformed token from node; check client version/format: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: A node sends an Authorization token whose value after the prefix is not valid standard base64: truncated token, token produced by a different/newer client format, token double-encoded or with URL-safe base64 instead of StdEncoding, or garbage/corrupted bytes in transit.

Common situations: Version skew between kops node binary (signer) and control-plane (verifier) changing token format; a proxy or middleware mangling the header; client sending an empty or differently formatted token; manual testing with curl pasting an incorrect token.

Related errors


AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05). Data as JSON: /api/errors/d75d860bf3a82bdd. Report an issue: GitHub.