question

Canberk Soner avatar image
Canberk Soner asked

Getting EntityTokenExpired on server

Hello,

One of our servers is getting EntityTokenExpired error when attempting to access entity API. We're using C# SDK from a .net core application.

The problem is that we do have code to get an entity token. This is the code we use to get a token:

            GetEntityTokenRequest tokenRequest = new GetEntityTokenRequest
            {
                Entity = new PlayFab.AuthenticationModels.EntityKey { Id = PlayFabSettings.staticSettings.TitleId, Type = "title" }
            };


            PlayFabResult<GetEntityTokenResponse> tokenResult = await
                PlayFabAuthenticationAPI.GetEntityTokenAsync(tokenRequest);

We do some operations in our server for every logging in player, so the token should not be expired because I'm refreshing it every time. Yet 24 hours after starting the server, it begins giving EntityTokenExpired errors, even though I'm making GetEntityToken requests.

How do I refresh this token without restarting the server? I assume token is set on playfab's static settings and since there's a value there, GetEntityToken call does not refresh it automatically?

We set the developer secret key earlier in the code like this:

PlayFabSettings.staticSettings.TitleId = <mytitleid>;
PlayFabSettings.staticSettings.DeveloperSecretKey = <mysecretkey>;
10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Citrus Yan avatar image
Citrus Yan answered

Referring to the following code snippet from GetEntityTokenAsync:

            var resultRawJson = (string)httpResult;
            var resultData = PluginManager.GetPlugin<ISerializerPlugin>(PluginContract.PlayFab_Serializer).DeserializeObject<PlayFabJsonSuccess<GetEntityTokenResponse>>(resultRawJson);
            var result = resultData.data;
            var updateContext = PlayFabSettings.staticPlayer;
            updateContext.EntityToken = result.EntityToken;
            updateContext.EntityId = result.Entity.Id;
            updateContext.EntityType = result.Entity.Type;
<br>

https://github.com/PlayFab/CSharpSDK/blob/c9f778bc2a18816819f0e799e20a897c0ed8c424/PlayFabSDK/source/PlayFabAuthenticationAPI.cs#L74

We can see that GetEntityTokenAsync do automatically refresh the token every time it’s called.

May I know are there any additional steps taken when (re)starting the server, would you please describe the basic flow? And, how do you call the entity APIs, can you share some sample code on that (feel free to obfuscate any sensitive info)?

10 comments
10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Canberk Soner avatar image Canberk Soner commented ·

Hello, I'll try to explain what we're doing more clearly. In addition to PlayFab, we also have a lobby server (.net core app, running playfab c# sdk) for more realtime stuff over tcp sockets (chats, notifications etc.)

1)Lobby server is launched. We generally launch a new server instance once every version, this is an application with long lifetime.

2)Lobby server sets which PlayFab title to connect to like this:

PlayFabSettings.staticSettings.TitleId = <mytitleid>;
PlayFabSettings.staticSettings.DeveloperSecretKey = <mysecretkey>;<br>

3)Any client logs in to PlayFab (unity client, playfab unity sdk)

4)Client sends PlayFab session ticket to lobby server

5)Lobby server validates session ticket with PlayFabServerAPI.AuthenticateSessionTicketAsync.

part1

1 Like 1 ·
Canberk Soner avatar image Canberk Soner commented ·

part2:

5)We now run some additional logic on title player entity.

First, we get entity token as a title (because this is our server app):

GetEntityTokenRequest tokenRequest = new GetEntityTokenRequest
            {
                Entity = new PlayFab.AuthenticationModels.EntityKey { Id = PlayFabSettings.staticSettings.TitleId, Type = "title" }
            };


PlayFabResult<GetEntityTokenResponse> tokenResult = await
                PlayFabAuthenticationAPI.GetEntityTokenAsync(tokenRequest);

We do not have any "store the token and check if 24 hours passed" kind of logic. Whenever a player logs in, the lobby server tries to refresh its token. We do not do anything with this tokenResult because as you said it is supposed to be automatic.

Then, we use entity api from c# sdk normally, example:

GetEntityProfileRequest request = new GetEntityProfileRequest
            {
                DataAsObject = true,
		Entity = new EntityKey
                {
                    Id = _titlePlayerId,
                    Type = "title_player_account"
                };

            };

PlayFabResult<GetEntityProfileResponse> result = await PlayFabProfilesAPI.GetProfileAsync(request);
1 Like 1 ·
Canberk Soner avatar image Canberk Soner commented ·

part3

Then we deploy this code and for 24 hours it runs without issues. After 24 hours, we begin receiving EntityTokenExpired on our api calls.

The weird thing is (I did not confirm this %100 yet), the request that returns "EntityTokenExpired" error is the request to refresh the entity token.

Any ideas what we might be missing here? Perhaps trying to refresh the token too often leads to a problem? Or is it possible to use the optional "AuthenticationContext" in the request parameters when calling the sdk methods to override static token and provide the newly received token?

Though this won't help with the get token request giving an error. Maybe the developer secret key assigned to the static playfab setting property "expires" somehow?

Any comments are welcome, really lost on this one :)

1 Like 1 ·
Citrus Yan avatar image Citrus Yan Canberk Soner commented ·

Not sure what's going on under the hood, looks like for some reasons the EntityToken does not get automatically refreshed, you may need to add some loggings to better find out what the root cause is.

Actually, in your case, I don't think it necessary to call GetEntityTokenAsync before doing some additional logic on title player entity every time a player logs in. When the player number is heavy, it could be less performant. I would recommend that you store the entity token on the server side, use AuthenticationContext to call entity APIs, and refresh it only when it expires.

0 Likes 0 ·
Canberk Soner avatar image Canberk Soner Citrus Yan commented ·

There really is nothing going on under the hood here to be honest, I shared almost all of the playfab code in the server (minus actual key/values etc.).

I'll try with AuthenticationContext and see what happens, I guess.

0 Likes 0 ·
Show more comments
andres-cichero avatar image
andres-cichero answered

We run into the same problem.

The solution, as mentioned, is to call PlayFabAuthenticationAPI.ForgetAllCredentials() before the actual call to PlayFabAuthenticationAPI.GetEntityTokenAsync().

To avoid calling PlayFabAuthenticationAPI.GetEntityTokenAsync() on every time, we implemented a wrapper method that calls PlayFabAuthenticationAPI.IsEntityLoggedIn() and then calls PlayFabAuthenticationAPI.GetEntityTokenAsync() only if it's needed.

After the actual API call, it checks for token expiration, and only it that case calls PlayFabAuthenticationAPI.ForgetAllCredentials() and performs the token renew.

private async Task<PlayFabResult<TResult>> CallAPI<TResult>(Func<Task<PlayFabResult<TResult>>> apiMethodCall) where TResult : PlayFabResultCommon
{
    if (PlayFabAuthenticationAPI.IsEntityLoggedIn() == false)
        await InitialisePlayFabSdk();

    var result = await apiMethodCall();

    if (result.Error?.Error == PlayFabErrorCode.EntityTokenExpired)
    {
        PlayFabAuthenticationAPI.ForgetAllCredentials();    //To avoid any EntityTokenExpired issue (MKNET-283)
        await InitialisePlayFabSdk();
        result = await apiMethodCall();
    }

    return result;
}


private async Task InitialisePlayFabSdk()
{
    PlayFabSettings.staticSettings.TitleId = _externalConfiguration.PlayFabAdminConfig?.TitleId ?? "";
    PlayFabSettings.staticSettings.DeveloperSecretKey = _externalConfiguration.PlayFabAdminConfig?.SecretKey ?? "";
    await PlayFabAuthenticationAPI.GetEntityTokenAsync(null);
}


/// Example
public async Task<ActionResult> Get(string buildId)
{
    var buildDetailsResponse = await CallAPI(async () =>
        await PlayFabMultiplayerAPI.GetBuildAsync(new GetBuildRequest
            {
                BuildId = buildId
            }));

    return buildDetailsResponse.Result;
}
10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

caglarenes avatar image
caglarenes answered
I had the same problem. Refleshing token before 1 hour from expiration time, solved my issue.
10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Write an Answer

Hint: Notify or tag a user in this post by typing @username.

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.