Cannot use ServiceToken for Remote Config in C# Module

Hi,

Why is this function locked to Client?

                var result = _gameApiClient.RemoteConfigSettings.AssignSettingsGetAsync(ctx, ctx.AccessToken, ctx.ProjectId,
                    ctx.EnvironmentId, null, new List<string> { configToFetch, k_GameConfigEvent });

I try to change ctx.AccessToken to ctx.ServiceToken (which works for cloud save etc.), since I am calling this cloud code via API there is no AccessToken available

Per the document this only has client auth. Why would ServiceAccount be excluded?
https://services.docs.unity.com/remote-config-client/v1/

There is no RemoteConfigSettings in IAdminApiClient either, even if there is get settings for admin api
https://services.docs.unity.com/remote-config-admin/v1/#tag/Purchases/operation/redeemGooglePlayPurchase

how do I make use of remote config without client auth in cloud code?

This is a great question! Have you found an answer?

Hey!

You don’t really need service authentication to get remote config, are you saying that you are calling this cloud code from a context other than a game client? i.e. who is calling cloud code in this use-case?

It’s also worth pointing out that a service account token and a service token are not quite the same, since you dont have to declare a server account in this case (which is done in the admin side of the dashboard) (i know that’s confusing, we have docs about it all, but it should be better).

It might be possible that a service token support wasn’t added since that doesnt allow clear application of “game overrides” for the specific client as applicable. Have you tried with the serviceToken? It could be that the it is supported, but not doucmented.

As you have noticed, you can technically use a service account token against the admin API, but I recommend against this, the admin API is rate-limited to admin-amount of actions, so it will hit a limit quickly.

Cheers!

Hi, the cloud code was to be called by REST API from a node server. In the end I set up a trigger (Cloud save: key-saved) that calls a cloud code module, so I can us context.ServiceToken for GameApiClient.EconomyCurrencies etc. but for remote config I still need a manual method as ServiceToken doesn’t work.

@Claytonious this is what I used for the time being

    private async Task<T> FetchRemoteConfigManually<T>(IExecutionContext ctx, string key)
    {
        try
        {
            ConfigResponse? resultData = new ConfigResponse();
            object? configValue = null;
            int retries = 0;
            string url = $"https://services.api.unity.com/remote-config/v1/projects/{ctx.ProjectId}/environments/{ctx.EnvironmentId}/configs";
            _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", $"{sa_k}:{sa_s}");
            bool found = false;
            while (retries < 3 && !found)
            {
                var response = await _httpClient.GetAsync(url);
                response.EnsureSuccessStatusCode();
                string jsonString = await response.Content.ReadAsStringAsync();
                resultData = JsonConvert.DeserializeObject<ConfigResponse>(jsonString);

                foreach (var value in resultData.Configs.FirstOrDefault().Value)
                {
                    if (value.Key == key)
                    {
                        configValue = value.Value;
                        found = true;
                        break;
                    }
                }
                await Task.Delay(k_FetchRetriesDelay);
                retries++;
            }
            return JsonConvert.DeserializeObject<T>(configValue.ToString());
        }
        catch (ApiException e)
        {
            _logger.LogError($"Failed to manually fetch all config from Remote Config. Error: {e.Message}");
            throw new Exception($"Failed to manually fetch all config from Remote Config. Error: {e.Message}");
        }
    }

// I also had to set this up manually
[Serializable]
public class ConfigItem
{
    [JsonProperty("projectId")]
    public string ProjectId { get; set; }

    [JsonProperty("environmentId")]
    public string EnvironmentId { get; set; }

    [JsonProperty("type")]
    public string Type { get; set; }

    [JsonProperty("value")]
    public List<ConfigValue> Value { get; set; }

    [JsonProperty("id")]
    public string Id { get; set; }

    [JsonProperty("version")]
    public string Version { get; set; }

    [JsonProperty("createdAt")]
    public DateTime CreatedAt { get; set; }

    [JsonProperty("updatedAt")]
    public DateTime UpdatedAt { get; set; }
}
[Serializable]
public class ConfigValue
{
    [JsonProperty("key")]
    public string Key { get; set; }

    [JsonProperty("type")]
    public string Type { get; set; }

    [JsonProperty("schemaId")]
    public string SchemaId { get; set; } // Use string to handle null as well

    [JsonProperty("value")]
    public object Value { get; set; } // Object list to handle flexible JSON
}
[Serializable]
public class ConfigResponse
{
    [JsonProperty("configs")]
    public List<ConfigItem> Configs { get; set; }
}

Hey,

Apologies, I’ve been preoccupied. Brought it up to the team, I have in the past added auth supported to services, it might be very simple, but it might be complicated, specially since there’s UI to update in the dashboard to give the service account the permission.

The best idea I can come up with is to authenticate your node server as an anonymous player, but will give you an update if the service account authentication can be added.

_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", $"{sa_k}:{sa_s}");

Also be aware that you should be converting to base 64, see CLI code here.

Additionally, the documentation of this sdk happens to cover pretty well what the clients can do out of the box.

Let me know if this helps,

Cheers

Gab

It seems that the AccessToken fails too if the Cloud Code module’s method that reads from RemoteConfig is executed using an ITrustedClient in client.CloudCode.RunModule() from the Unity Editor.

I get a:

Unity.Services.CloudCode.Shared.ApiException: Unauthorized 
at Unity.Services.CloudCode.Shared.HttpApiClient.ToApiResponse[T](HttpResponseMessage response) 
at Unity.Services.CloudCode.Shared.HttpApiClient.SendAsync[T](String path, HttpMethod method, ApiRequestOptions options, IApiConfiguration configuration, CancellationToken cancellationToken) 
at Unity.Services.RemoteConfig.Api.RemoteConfigSettingsApi.AssignSettingsGetAsync(IExecutionContext executionContext, String accessToken, String projectId, String environmentId, String configType, List`1 key, List`1 type, CancellationToken cancellationToken) 
at <my code calling AssignSettingsGetAsync>

If it can help:

  • The same code works without issues when playing from the Unity Editor’s player or from a build.
  • The code without the call AssignSettingsGetAsync to Remote Config works in all situations
  • I already gave my service account all remote-config-related permissions in the Unity Dashboard, just in case (Remote Config Admin, API Viewer, API Editor)
  • I removed all access policies and set one as “allow all” just in case

Any idea on how to solve this? In the current state all Cloud Code methods that involve Remote Config and are called from editor tools with ITrustedClient will fail.

Answering back here just for full context. RikuTheFuffs had a conversation with my colleague and the recommendation was to use the service token (not to be confused with service account), to call the admin API directly.
In the context of a tool that already has trusted-level authority, I would recommend to not call Cloud-Code at all. Just call the individual services directly.

If in your context for whatever reason, you need/want to pass by cloud-code or are running a custom server, you can either authenticate anonymously separately within that server’s context, or use a service account token (as I described earlier in the thread) to call the admin API and cache the response. Be aware that Cloud-Code’s APIs out-of-the-box Nuget only include admin APIs for Cloud Save, Cloudcode, and Leaderboards, AFAIK, I need to ask the Cloud-code team to include RC admin.

For the latter, there’s 2 caveats:

  • Admin APIs aren’t designed for heavy throughput and are strongly rate-limited
  • Since you’re not going through the runtime API, game-overrides , filters, etc are unavailable; you’re getting the raw admin API

I think I’m in the same boat. I have a realtime server that authenticates through a service token. When I try to fetch Remote config, it returns empty (no keys, no values). Whereas on the client the exact same code returns the correct keys. The only difference I can see is regular auth vs service token auth using

await ServerAuthenticationService.Instance.SignInWithServiceAccountAsync(serviceAccountId, serviceAccountSecret);

EDIT: the service account has the project-level remote config viewer permissions.
EDIT2: Confirmed that both initialize unity services with the same environment.