How to resolve "anonymous access not permitted for agent"

When the events get posted, the following error can occur despite setting the secret token in the configuration:

{PayloadSenderV2} Failed sending event. Events intake API absolute URL: https://acme.apm.eu-west-1.aws.cloud.es.io/intake/v2/events. APM Server response: status code: Forbidden, content:
{"accepted":0,"errors":[{"message":"cannot handle stream: cannot process batch: unauthorized: anonymous access not permitted for agent "dotnet""}]}

The cause was that in my case the deserialization from JSON to an IConfigurationReader defaulted to the use of String.Empty instead of null for null values in the JSON configuration file appsettings.*.json, including for ApiKey:

image

However, the Elastic APM .net agent 1.27.0 does not use String.IsNullOrEmpty but == null in many locations, including BackendCommUtils.cs method BuildHttpClient:

	if (configuration.ApiKey != null)
		httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("ApiKey", configuration.ApiKey);
	else if (configuration.SecretToken != null)
		httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", configuration.SecretToken);

This comparison will fail when an empty string is presented.

To avoid signing off many pages of legal text to enable a PR, we have made the following change in the implementation of IConfigurationReader:

        private string? apiKey;
        /// <summary>
        /// The API key used to send data to the APM server.
        /// Ensures that only your agents can send data to your APM server.
        /// </summary>
        [NSJ.JsonProperty("ApiKey")]
        [STJ.JsonPropertyName("ApiKey")]
        [ConfigurationKeyName("ApiKey")]
        public string? ApiKey 
        { 
            get
            {
                //
                // Workaround for Elastic APM nuget package testing on null instead of String.IsNullOrEmpty().
                //
                if (string.IsNullOrEmpty(this.apiKey))
                {
                    return null;
                }
                else
                {
                    return this.apiKey;
                }
            }
            set
            {
                this.apiKey = value;
            }
        }