{"record":{"id":"a2f0c14e4cd1d58b","repo":"kubernetes/kops","slug":"unmarshalling-authorization-token-w-a2f0c1","errorCode":null,"errorMessage":"unmarshalling authorization token: %w","messagePattern":"unmarshalling authorization token: %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"upup/pkg/fi/cloudup/gce/tpm/gcetpmverifier/tpmverifier.go","lineNumber":90,"sourceCode":"var _ bootstrap.Verifier = (*tpmVerifier)(nil)\n\nfunc (v *tpmVerifier) VerifyToken(ctx context.Context, rawRequest *http.Request, authToken string, body []byte) (*bootstrap.VerifyResult, error) {\n\t// Reminder: we shouldn't trust any data we get from the client until we've checked the signature (and even then...)\n\t// Thankfully the GCE SDK does seem to escape the parameters correctly, for example.\n\n\tif !strings.HasPrefix(authToken, gcetpm.GCETPMAuthenticationTokenPrefix) {\n\t\treturn nil, bootstrap.ErrNotThisVerifier\n\t}\n\tauthToken = strings.TrimPrefix(authToken, gcetpm.GCETPMAuthenticationTokenPrefix)\n\n\ttokenBytes, err := base64.StdEncoding.DecodeString(authToken)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"decoding authorization token: %w\", err)\n\t}\n\n\ttoken := &gcetpm.AuthToken{}\n\tif err = json.Unmarshal(tokenBytes, token); err != nil {\n\t\treturn nil, fmt.Errorf(\"unmarshalling authorization token: %w\", err)\n\t}\n\n\ttokenData := gcetpm.AuthTokenData{}\n\tif err := json.Unmarshal(token.Data, &tokenData); err != nil {\n\t\treturn nil, fmt.Errorf(\"unmarshalling authorization token data: %w\", err)\n\t}\n\n\t// Guard against replay attacks\n\tif tokenData.Audience != gcetpm.AudienceNodeAuthentication {\n\t\treturn nil, fmt.Errorf(\"incorrect Audience\")\n\t}\n\ttimeSkew := math.Abs(time.Since(time.Unix(tokenData.Timestamp, 0)).Seconds())\n\tif timeSkew > float64(v.opt.MaxTimeSkew) {\n\t\treturn nil, fmt.Errorf(\"incorrect Timestamp %v\", tokenData.Timestamp)\n\t}\n\n\t// Verify the token has signed the body content.\n\trequestHash := sha256.Sum256(body)","sourceCodeStart":72,"sourceCodeEnd":108,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/upup/pkg/fi/cloudup/gce/tpm/gcetpmverifier/tpmverifier.go#L72-L108","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"tokenBytes, err := base64.StdEncoding.DecodeString(b64)\nif err != nil { return err }\nvar probe map[string]json.RawMessage\nif err := json.Unmarshal(tokenBytes, &probe); err != nil {\n    return fmt.Errorf(\"payload is not a JSON object\")\n}\nif _, ok := probe[\"Data\"]; !ok {\n    return fmt.Errorf(\"missing Data field\")\n}","typeGuard":"func looksLikeAuthToken(tokenBytes []byte) bool {\n    var probe struct {\n        Data      json.RawMessage `json:\"Data\"`\n        Signature json.RawMessage `json:\"Signature\"`\n    }\n    return json.Unmarshal(tokenBytes, &probe) == nil && len(probe.Data) > 0\n}","tryCatchPattern":"token, err := verifier.VerifyToken(ctx, rawToken, request)\nif err != nil && strings.Contains(err.Error(), \"unmarshalling authorization token\") {\n    return fmt.Errorf(\"incompatible token schema; align node/verifier versions: %w\", err)\n}","preventionTips":["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"],"tags":["gce","tpm","json","token-validation"],"backgroundTag":"malformed-auth-token","analyzedSha":"4c8573c808a73d578c5eadc86d410646ea0b0d73","analyzedAt":"2026-09-05T04:13:19.212Z","contentChangedAt":"2026-09-05T04:13:19.212Z","schemaVersion":2},"datasetVersion":"2026-09-12T12:17:11.808Z"}