Skip to content
This repository was archived by the owner on Sep 21, 2022. It is now read-only.

Authentication And Security

Scott edited this page Aug 2, 2020 · 8 revisions

The mod.io API uses two forms of authentication:

  • An API Key for unauthenticated users that is unique to a game profile.
  • An OAuthToken for authenticated users that is unique to a user on a per profile basis. This topic is covered in detail in the mod.io API documentation, and it is recommended reading for a better understanding of the authentication process. It is briefly covered below as to how it pertains to mod.io UNITY.

Game Profile API Key and ID

A Game Profile API Key allows GET requests to to be sent to the API for the purpose of browsing and downloading mod profiles. Requests sent using an API Key are currently not limited in number (see: Rate Limiting) but offer only a very restricted set of privileges, and thus we recommend that most apps encourage players to sign-in to allow a better understanding of their player-base, and facilitate community interaction.

The mod.io Unity Plugin is designed to be used in conjunction with a single game ID and API Key pair. To this end, selecting the menu item mod.io/Edit Settings creates or highlights the instance of a PluginSettings object saved with the file name described by PluginSettings.FILE_PATH ("modio_settings" by default) in a Unity Resources folder. The data in this asset is referenced by multiple mod.io classes during static initialization to set the variables that should not be changed during the program lifetime.

The API key and Id for a mod.io game profile can be located at either of https://mod.io/apikey/ or https://test.mod.io/apikey/, for the production and test servers respectively. This page will display all of the ids and API keys connected to a specific account, and can be easily accessed through the PluginSettings inspector.

NOTE: ALL Profiles (Game and User Accounts) are unique the environment in which they were created. Thus, the details and authentication credentials generated on the test server are in no way linked to those generated on the production server. In effect, this means that an app that has been using one set of credentials in testing, will need those updated to reflect the production server values in order to function correctly on release.

User Authentication

A valid OAuthToken submitted an API request allows the API to authenticate the user attempting the request, facilitating the use of POST, PUT, and DELETE methods; requests that involve uploading and updating data on the server such as uploading of mods, sending user ratings, and subscribing to mod profiles. Requesting this token is outlined in the 'Email Authentication Flow' under the Authentication section in the mod.io API documentation. In brief: the user supplies an email address (that may or may not belong to an existing user account), is sent an email containing a security code, and then inputs the code into the game or app to authenticate.

mod.io UNITY provides a native interface for this, in APIClient:

  • APIClient.SendSecurityCode requires an email address for the user attempting to log into the game or app, and will instruct the mod.io server to send a single-use security code to the provided email address.
  • APIClient.GetOAuthToken requires a security code (the one the user has received via email via APIClient.SendSecurityCode), and responds to the query with the string representation of the OAuthToken matching the given security code.

UserAuthenticationData.instance provides an easy way of managing the authenticated user's data, maintaining this information in a small file in the cache directory across sessions. Calls made by APIClient will provide the authentication token stored as part of the web request, and a missing token will render the APIClient unable to successfully make POST, PUT, and DELETE requests.

Authentication via Steam

If you haven't done so already, you need to generate and set Encrypted App Ticket Key in your Steamworks App Admin: Select game, under Technical Tools, select Edit Steamworks Settings, under Security, select SDK Auth; click Generate and don't forget to also click Set. You may need to publish this change.

Copy the generated key into your mod.io game settings: Select game, Edit, Options, API Authentication via Steam.

Using Facepunch.Steamworks

If you are using Facepunch.Steamworks, authentication is very easy:

using UnityEngine;

using ModIO;
using Steamworks;

public class ModIOAuthenticateViaFacepunchSteam : MonoBehaviour {

    public async void OnEnable() {
        Log("Requesting encrypted app ticket from Steam");
        byte[] encryptedTicket = null;
        encryptedTicket = await SteamUser.RequestEncryptedAppTicketAsync();
        
        Log("App ticket received, now trying authentication on mod.io");
        UserAccountManagement.AuthenticateWithSteamEncryptedAppTicket(
            encryptedTicket, (uint)encryptedTicket.Length,
            (u) => {
                Log("Player is now authenticated to mod.io via Facepunch.Steamworks");
            },
            (e) => { 
                LogError($"Authentication failed {e.errorMessage} / {e.displayMessage}");
            });
        
    }

    #region Logging
    // passing a prefix makes it easy to filter log statements of this subsystem
    private const string LOGPREFIX = "<b>[mod.io/Facepunch.Steam]</b>";
    
    private void Log(string msg) {
        Debug.Log($"{LOGPREFIX} {msg}");
    }
    
    private void LogError(string msg) {
        Debug.LogError($"{LOGPREFIX} {msg}");
    }
    #endregion Logging
}

NOTE: This is on Unity 2019.1, with Scripting Runtime Version set to .NET 4.x Equivalent in the Project Settings. Earlier .NET versions (2.0/3.5) do not support the $ - string interpolation syntax used in the logging statements, so you'd have to use Debug.LogFormat() or string.Format() instead. See Async-Await instead of coroutines in Unity 2017 for more details on using async-await in Unity.

Using Steamworks.NET

If you are using Steamworks.NET, you have more control but also need much more code:

using UnityEngine;

using ModIO;
using SteamworksNET; // usually just Steamworks

public class ModIOAuthenticateViaSteamworksNET : MonoBehaviour {

    private CallResult<EncryptedAppTicketResponse_t> OnEncryptedAppTicketResponseCallResult;
    
    public void OnEnable() {
        OnEncryptedAppTicketResponseCallResult = 
            CallResult<EncryptedAppTicketResponse_t>.Create(OnEncryptedAppTicketResponse);
        
        Log("Requesting encrypted app ticket from Steam");
        byte[] randomData = new byte[0]; // RequestEncryptedAppTicket needs that parameter, but it's irrelevant
        SteamAPICall_t handle = SteamUser.RequestEncryptedAppTicket(randomData, sizeof(uint));
        OnEncryptedAppTicketResponseCallResult.Set(handle);
    }

    private void OnEncryptedAppTicketResponse(EncryptedAppTicketResponse_t callback, bool ioFailure) {
        if (ioFailure) {
            LogError("Failed because IO Failure");
            return;
        }

        if (callback.m_eResult != EResult.k_EResultOK) {
            LogError("Failed because callback result was not OK");
            return;
        }

        Log("Obtaining requested encrypted app ticket");
        byte[] encryptedTicket = new byte[1024];
        if (SteamUser.GetEncryptedAppTicket(encryptedTicket, 1024, out uint ticketLength)) {
            Log("App ticket received, now trying authentication on mod.io");
            UserAccountManagement.AuthenticateWithSteamEncryptedAppTicket(
                encryptedTicket, ticketLength,
                (u) => {
                    Log("mod.io is now authenticated via Steamworks.NET");
                },
                (e) => { 
                    LogError($"Authentication failed {e.errorMessage} / {e.displayMessage}");
                });
        } else {
            LogError("Failed because ticket could not be obtained.");
        }
    }

    #region Logging
    // passing a prefix makes it easy to filter log statements of this subsystem
    private const string LOGPREFIX = "<b>[mod.io/Steamworks.NET]</b>";
    
    private void Log(string msg) {
        Debug.Log($"{LOGPREFIX} {msg}");
    }
    
    private void LogError(string msg) {
        Debug.LogError($"{LOGPREFIX} {msg}");
    }
    #endregion Logging
}

NOTE: This example requires Scripting Runtime Version set to .NET 4.x Equivalent in the Project Settings. Earlier .NET versions (2.0/3.5) do not support the $ - string interpolation syntax used in the logging statements, so you'd have to use Debug.LogFormat() or string.Format() instead.

Clone this wiki locally