kubernetes/kops · error

invalid authorization token

Error message

invalid authorization token

What it means

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.

Source

Thrown at upup/pkg/fi/cloudup/linode/verifier.go:72

	if err != nil {
		return nil, fmt.Errorf("failed to create Linode client: %w", err)
	}
	client.SetUserAgent("kops")
	client.SetToken(accessToken)

	return &linodeVerifier{client: &client}, nil
}

// VerifyToken verifies that the given token corresponds to a valid Akamai (Linode) instance.
func (v *linodeVerifier) VerifyToken(ctx context.Context, rawRequest *http.Request, token string, body []byte) (*bootstrap.VerifyResult, error) {
	if !strings.HasPrefix(token, linodemetadata.LinodeAuthenticationTokenPrefix) {
		return nil, bootstrap.ErrNotThisVerifier
	}

	instanceIDString := strings.TrimPrefix(token, linodemetadata.LinodeAuthenticationTokenPrefix)
	instanceID, err := strconv.Atoi(instanceIDString)
	if err != nil {
		return nil, fmt.Errorf("invalid authorization token")
	}

	instance, err := v.client.GetInstance(ctx, instanceID)
	if err != nil {
		return nil, fmt.Errorf("failed to get info for Akamai (Linode) instance %q: %w", instanceIDString, err)
	}
	if instance == nil {
		return nil, fmt.Errorf("failed to get info for Akamai (Linode) instance %q: empty response", instanceIDString)
	}

	addresses, challengeEndpoints := gatherIPv4Addresses(instance.IPv4)
	if len(challengeEndpoints) == 0 {
		return nil, fmt.Errorf("cannot determine challenge endpoint for instance id: %s", instanceIDString)
	}

	result := &bootstrap.VerifyResult{
		NodeName:          instance.Label,
		InstanceGroupName: instanceGroupNameFromTags(instance.Tags),

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Ensure the client sends prefix + numeric instance ID exactly as defined in linodemetadata.LinodeAuthenticationTokenPrefix
  2. Check client/server kOps versions match so the token format is identical
  3. Log the received token shape (prefix only, never the secret) to see what the suffix actually contains
  4. If you control the caller, strconv-quote or sanitize the ID before composing the token

Example fix

// before (caller)
token := linodemetadata.LinodeAuthenticationTokenPrefix + instanceLabel
// after (caller)
token := linodemetadata.LinodeAuthenticationTokenPrefix + strconv.Itoa(instanceID)
Defensive patterns

Strategy: validation

Validate before calling

idStr := strings.TrimPrefix(token, linodemetadata.LinodeAuthenticationTokenPrefix)
if _, err := strconv.Atoi(idStr); err != nil {
	return errors.New("token must be " + linodemetadata.LinodeAuthenticationTokenPrefix + "<numeric-instance-id>")
}

Type guard

func isValidLinodeAuthToken(token string) bool {
	idStr := strings.TrimPrefix(token, linodemetadata.LinodeAuthenticationTokenPrefix)
	_, err := strconv.Atoi(idStr)
	return err == nil
}

Try / catch

result, err := verifier.VerifyToken(ctx, token, certificates, challenge)
if err != nil {
	if strings.Contains(err.Error(), "invalid authorization token") {
		return errors.New("client sent malformed token; expected prefix + numeric instance id")
	}
	return err
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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