Skip to content

Connect to PlayFab PubSub

Authenticator implementation that can be used with PlayFab:

using System;

namespace Best.SignalR.Authentication
{
    public sealed class PlayFabAuthenticator : IAuthenticationProvider
    {
        /// <summary>
        /// No pre-auth step required for this type of authentication
        /// </summary>
        public bool IsPreAuthRequired { get { return false; } }

    #pragma warning disable 0067
        /// <summary>
        /// Not used event as IsPreAuthRequired is false
        /// </summary>
        public event OnAuthenticationSuccededDelegate OnAuthenticationSucceded;

        /// <summary>
        /// Not used event as IsPreAuthRequired is false
        /// </summary>
        public event OnAuthenticationFailedDelegate OnAuthenticationFailed;

    #pragma warning restore 0067

        private HubConnection _connection;
        private string _entityToken;

        public PlayFabAuthenticator(HubConnection connection, string entityToken)
        {
            this._connection = connection;
            this._entityToken = entityToken;
        }

        /// <summary>
        /// Not used as IsPreAuthRequired is false
        /// </summary>
        public void StartAuthentication() { }

        /// <summary>
        /// Prepares the request by adding two headers to it
        /// </summary>
        public void PrepareRequest(Best.HTTP.HTTPRequest request)
        {
            if (this._connection.NegotiationResult == null) {
                request.SetHeader("X-EntityToken", this._entityToken);
                return;
            }

            // Add Authorization header to http requests, add access_token param to the uri otherwise
            if (Best.HTTP.Hosts.Connections.HTTPProtocolFactory.GetProtocolFromUri(request.CurrentUri) == Best.HTTP.Hosts.Connections.SupportedProtocols.HTTP)
                request.SetHeader("Authorization", "Bearer " + this._connection.NegotiationResult.AccessToken);
            else
    #if !BESTHTTP_DISABLE_WEBSOCKET
                if (Best.HTTP.Hosts.Connections.HTTPProtocolFactory.GetProtocolFromUri(request.Uri) != Best.HTTP.Hosts.Connections.SupportedProtocols.WebSocket)
                request.Uri = PrepareUriImpl(request.Uri);
    #else
                ;
    #endif
        }

        public Uri PrepareUri(Uri uri)
        {
            if (this._connection.NegotiationResult == null)
                return uri;

            if (uri.Query.StartsWith("??"))
            {
                UriBuilder builder = new UriBuilder(uri);
                builder.Query = builder.Query.Substring(2);

                return builder.Uri;
            }

    #if !BESTHTTP_DISABLE_WEBSOCKET
            if (Best.HTTP.Hosts.Connections.HTTPProtocolFactory.GetProtocolFromUri(uri) == Best.HTTP.Hosts.Connections.SupportedProtocols.WebSocket)
                uri = PrepareUriImpl(uri);
    #endif

            return uri;

        }

        private Uri PrepareUriImpl(Uri uri)
        {
            if (this._connection.NegotiationResult != null && !string.IsNullOrEmpty(this._connection.NegotiationResult.AccessToken))
            {
                string query = string.IsNullOrEmpty(uri.Query) ? "" : uri.Query + "&";
                UriBuilder uriBuilder = new UriBuilder(uri.Scheme, uri.Host, uri.Port, uri.AbsolutePath, query + "access_token=" + this._connection.NegotiationResult.AccessToken);
                return uriBuilder.Uri;
            }

            return uri;
        }

        public void Cancel() { }
    }
}

The only main change differentiating it from the default access-token authenticator is that this one sets the X-EntityToken header in the PrepareRequest method.

And it can be used while setting up the HubConnection object:

1
2
3
4
5
6
7
8
9
string titleId = "...";
string entityToken = "...";

var connection = new HubConnection(new Uri($"https://{titleId}.playfabapi.com/pubsub"), new JsonProtocol(new LitJsonEncoder()));
connection.AuthenticationProvider = new PlayFabAuthenticator(connection, entityToken);

// add callbacks, etc.

connection.StartConnect();

Comments