kubernetes/kops · error
unmarshalling authorization token: %w
Error message
unmarshalling authorization token: %w
What it means
After base64 decoding, VerifyToken unmarshals the bytes into gcetpm.AuthToken {Data []byte, Signature []byte}. If json.Unmarshal fails, the token bytes are not the expected JSON structure — the payload is corrupt or from an incompatible format.
Source
Thrown at upup/pkg/fi/cloudup/gce/tpm/gcetpmverifier/tpmverifier.go:90
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) {
return nil, fmt.Errorf("incorrect Timestamp %v", tokenData.Timestamp)
}
// Verify the token has signed the body content.
requestHash := sha256.Sum256(body)View on GitHub (pinned to 4c8573c808)
Solutions
- Rebuild/redeploy node and control-plane components so both use the same gcetpm.AuthToken schema
- Inspect the decoded payload (echo <token> | base64 -d) to see its actual structure
- Ensure the client signs via gcetpm authenticator, not another auth mechanism
- Add no manual JSON construction — always produce tokens via CreateToken
Defensive patterns
Strategy: validation
Validate before calling
tokenBytes, err := base64.StdEncoding.DecodeString(b64)
if err != nil { return err }
var probe map[string]json.RawMessage
if err := json.Unmarshal(tokenBytes, &probe); err != nil {
return fmt.Errorf("payload is not a JSON object")
}
if _, ok := probe["Data"]; !ok {
return fmt.Errorf("missing Data field")
} Type guard
func looksLikeAuthToken(tokenBytes []byte) bool {
var probe struct {
Data json.RawMessage `json:"Data"`
Signature json.RawMessage `json:"Signature"`
}
return json.Unmarshal(tokenBytes, &probe) == nil && len(probe.Data) > 0
} Try / catch
token, err := verifier.VerifyToken(ctx, rawToken, request)
if err != nil && strings.Contains(err.Error(), "unmarshalling authorization token") {
return fmt.Errorf("incompatible token schema; align node/verifier versions: %w", err)
} Prevention
- Test CreateToken/VerifyToken round-trips in CI across upgrades
- Avoid hand-crafted tokens in tests; use CreateToken
- Share one gcetpm package definition between client and server
When it happens
Trigger: json.Unmarshal(tokenBytes, token) fails: token payload is valid base64 but not the expected JSON object with Data/Signature fields (wrong types, e.g. strings instead of base64 byte fields, or arbitrary non-JSON content).
Common situations: Client/verifier version skew changing the AuthToken shape; a test token built by hand with wrong field types; another token format (e.g. JWT) sent where the GCE TPM token is expected.
Related errors
- failed to marshal token data: %w
- failed to marshal token: %w
- decoding authorization token: %w
- unmarshalling authorization token data: %w
- failed to get GCE RSA attestation key from TPM: %w
AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05).
Data as JSON: /api/errors/a2f0c14e4cd1d58b.
Report an issue: GitHub.