{"record":{"id":"d921c7ac88ca2220","repo":"kubernetes/kops","slug":"invalid-authorization-token-d921c7","errorCode":null,"errorMessage":"invalid authorization token","messagePattern":"invalid authorization token","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"upup/pkg/fi/cloudup/linode/verifier.go","lineNumber":72,"sourceCode":"\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to create Linode client: %w\", err)\n\t}\n\tclient.SetUserAgent(\"kops\")\n\tclient.SetToken(accessToken)\n\n\treturn &linodeVerifier{client: &client}, nil\n}\n\n// VerifyToken verifies that the given token corresponds to a valid Akamai (Linode) instance.\nfunc (v *linodeVerifier) VerifyToken(ctx context.Context, rawRequest *http.Request, token string, body []byte) (*bootstrap.VerifyResult, error) {\n\tif !strings.HasPrefix(token, linodemetadata.LinodeAuthenticationTokenPrefix) {\n\t\treturn nil, bootstrap.ErrNotThisVerifier\n\t}\n\n\tinstanceIDString := strings.TrimPrefix(token, linodemetadata.LinodeAuthenticationTokenPrefix)\n\tinstanceID, err := strconv.Atoi(instanceIDString)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"invalid authorization token\")\n\t}\n\n\tinstance, err := v.client.GetInstance(ctx, instanceID)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get info for Akamai (Linode) instance %q: %w\", instanceIDString, err)\n\t}\n\tif instance == nil {\n\t\treturn nil, fmt.Errorf(\"failed to get info for Akamai (Linode) instance %q: empty response\", instanceIDString)\n\t}\n\n\taddresses, challengeEndpoints := gatherIPv4Addresses(instance.IPv4)\n\tif len(challengeEndpoints) == 0 {\n\t\treturn nil, fmt.Errorf(\"cannot determine challenge endpoint for instance id: %s\", instanceIDString)\n\t}\n\n\tresult := &bootstrap.VerifyResult{\n\t\tNodeName:          instance.Label,\n\t\tInstanceGroupName: instanceGroupNameFromTags(instance.Tags),","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/upup/pkg/fi/cloudup/linode/verifier.go#L54-L90","documentation":"VerifyToken authenticates node bootstrap requests. The presented token must have the linodemetadata.LinodeAuthenticationTokenPrefix; the suffix is expected to be the numeric Linode instance ID. If the suffix does not parse as an integer via strconv.Atoi, the token is rejected with 'invalid authorization token'. It is a static message — the underlying parse error is deliberately not included.","triggerScenarios":"A client presents a token with the correct prefix but a non-numeric remainder (e.g. 'linode:abc123'), or an empty remainder (bare prefix), so strconv.Atoi fails. Called from bootstrap verification flow; exercised by TestLinodeVerifierVerifyToken* tests.","commonSituations":"Node agent configured with a raw API token instead of the expected 'prefix+instanceID' composite token; version mismatch between the client that mints tokens and the verifier's expected format; manual curl testing against the verifier endpoint with a made-up token; whitespace or URL-encoding corrupting the ID.","solutions":["Ensure the client sends prefix + numeric instance ID exactly as defined in linodemetadata.LinodeAuthenticationTokenPrefix","Check client/server kOps versions match so the token format is identical","Log the received token shape (prefix only, never the secret) to see what the suffix actually contains","If you control the caller, strconv-quote or sanitize the ID before composing the token"],"exampleFix":"// before (caller)\ntoken := linodemetadata.LinodeAuthenticationTokenPrefix + instanceLabel\n// after (caller)\ntoken := linodemetadata.LinodeAuthenticationTokenPrefix + strconv.Itoa(instanceID)","handlingStrategy":"validation","validationCode":"idStr := strings.TrimPrefix(token, linodemetadata.LinodeAuthenticationTokenPrefix)\nif _, err := strconv.Atoi(idStr); err != nil {\n\treturn errors.New(\"token must be \" + linodemetadata.LinodeAuthenticationTokenPrefix + \"<numeric-instance-id>\")\n}","typeGuard":"func isValidLinodeAuthToken(token string) bool {\n\tidStr := strings.TrimPrefix(token, linodemetadata.LinodeAuthenticationTokenPrefix)\n\t_, err := strconv.Atoi(idStr)\n\treturn err == nil\n}","tryCatchPattern":"result, err := verifier.VerifyToken(ctx, token, certificates, challenge)\nif err != nil {\n\tif strings.Contains(err.Error(), \"invalid authorization token\") {\n\t\treturn errors.New(\"client sent malformed token; expected prefix + numeric instance id\")\n\t}\n\treturn err\n}","preventionTips":["Mint tokens only via the shared linodemetadata helpers so prefix+ID format stays consistent","Keep client and verifier kOps versions aligned","Never send raw API tokens where the composite bootstrap token is expected","Sanitize/trim the instance ID before composing the token"],"tags":["authentication","token","linode","bootstrap"],"backgroundTag":"invalid-auth-token","analyzedSha":"4c8573c808a73d578c5eadc86d410646ea0b0d73","analyzedAt":"2026-09-05T04:13:19.212Z","contentChangedAt":"2026-09-05T04:13:19.212Z","schemaVersion":2},"datasetVersion":"2026-09-12T07:17:12.445Z"}