Skip to content

Step 2. Log in

Implement login so that users can log in to your app with their Steam account without a separate sign-up. Before you begin, complete Step 1. Set up the integration.

For Steam login, how you get credentials depends on the OS the app runs on. Both methods return values that the Hive Axyl authentication server can verify directly, so you log in with the Direct Token flow without an exchange step.

1. Get Steam credentials

Get Steam credentials with the method that matches the OS the app runs on.

1.1. Windows and macOS

On Windows and macOS, the Steam login Add-on gets an authentication ticket from Steamworks. Because the user is already logged in to the Steam client, no separate login screen appears.

Request an authentication ticket

Method

GetAuthTicketForWebApiAsync

Call ISteamPlugin.GetAuthTicketForWebApiAsync() to get an authentication ticket. The ticket is returned as a hexadecimal string, and you use it as ProviderToken in the login request.

Field name Type Required Description
Identity string Required The identification string that Steamworks uses when it creates the ticket. If you pass an empty string, Steamworks uses its default identifier. Steamworks rejects values longer than 30 characters.
using Hive.Axyl.Auth.Addon.Steam;
using Hive.Axyl.Core;
using UnityEngine;

// The Add-on is registered only in Windows and macOS builds.
if (!HiveCore.TryResolve<ISteamPlugin>(out var steam))
{
    // Not Windows or macOS, or the Add-on is not registered → branch to the web login session
    return;
}

var ticketResult = await steam.GetAuthTicketForWebApiAsync(
    new GetAuthTicketForWebApiRequest { Identity = string.Empty });

string steamProviderToken;   // ProviderToken of the login request
switch (ticketResult)
{
    case SteamServiceGetAuthTicketForWebApiResult.Success success:
        steamProviderToken = success.Data.TicketHex;
        break;

    case SteamServiceGetAuthTicketForWebApiResult.NotAuthenticated:
        // Not logged in to the Steam client → prompt the user to log in to Steam
        return;

    case SteamServiceGetAuthTicketForWebApiResult.Failure failure:
        HiveError err = failure.Problem;
        Debug.LogError($"[{err.Code}] {err.Message} (trace: {err.TraceId})");
        return;

    // Safety net: unhandled results and unknown new results (UnknownOutcome)
    default:
        Debug.LogWarning($"Unhandled result: {ticketResult.GetType().Name}");
        return;
}

// Steam ID64 of the user currently logged in to the Steam client.
string steamProviderUserId = GetCurrentSteamId64();

GetCurrentSteamId64() is code that the app implements itself to read the current user's Steam ID64 from Steamworks. The Steam login Add-on does not provide this value.

Note

The Hive Axyl authentication server confirms the actual Steam account by checking the authentication ticket with Steam. The Steam ID64 that the app sends does not replace that confirmation process.

Response status

Response case Description App client handling
Success Ticket issued successfully. Use Data.TicketHex as ProviderToken. Proceed with external authentication provider login
NotAuthenticated When the user is not logged in to the Steam client Prompt the user to log in to the Steam client
UnknownOutcome A new result that this SDK version does not recognize Log it and handle it conservatively
Failure Common Failure. The case where Steamworks has not been initialized (FailedPrecondition) also branches here, and the cause is in Failure.Problem.Code. See Common error handling. Handle according to the common error handling criteria

Release the authentication ticket

Method

ReleaseTicket

Steam limits the number of authentication tickets that an app can hold at the same time. If you keep issuing tickets without releasing them, later issuance requests fail, so release the ticket with ReleaseTicket() after you receive the login result.

Release the ticket after you receive the response from Log in with an external authentication provider, whether the login succeeded or failed. If you release it before verification finishes, Steam considers the ticket invalid and login fails.

using Hive.Axyl.Auth.Addon.Steam;
using Hive.Axyl.Core;

// Call this after you receive the external authentication provider login result.
if (HiveCore.TryResolve<ISteamPlugin>(out var steam))
{
    steam.ReleaseTicket(steamProviderToken);
}

Call ReleaseTicket() on the Unity main thread. Passing a ticket that was already released or is unknown does nothing.

1.2. OSs other than Windows and macOS

On Android and iOS, open the Steam login page with a web login session and receive Steam's OpenID login result. Because Steam does not send the login result back to the app's own scheme URL, the result returns to the app callback URL through the Hive Axyl relay URL. Use the received result for login as is, without an exchange step.

The app gets Steam credentials in the following order.

  1. Create a return_to URL with a new random value and store it.
  2. Build a Steam login request URL that includes the return_to URL.
  3. Put the app callback URL in OpenRequest.RedirectUri and open a web login session.
  4. Verify the callback.
  5. Extract the values for ProviderUserId and ProviderToken from the callback.

Build the return_to URL

The return_to URL is the URL to which Steam sends the login result. Build it by appending the app callback URL and a random value as query parameters to the Hive Axyl relay URL.

https://core-api.hiveaxyl.com/auth/v1/provider/callback?relayTo={URL-encoded app callback URL}&s={random value}
  • relayTo: The URL-encoded value of the app callback URL {appId}://oauth-callback, to which the Hive Axyl relay URL delivers the result
  • s: A cryptographically secure random value that you create anew for every login attempt. The example code generates it with CreateNonce(), defined in Sign in with Apple

Steam returns the return_to URL as is in the login result, so store the URL you created and compare it in Verify the callback. The app callback URL is the value you decided in Relay URL and app callback URL.

Build the login request URL

Build the login request URL by appending the following parameters to the Steam OpenID login endpoint https://steamcommunity.com/openid/login. URL-encode each value.

  • openid.ns: http://specs.openid.net/auth/2.0
  • openid.mode: checkid_setup
  • openid.return_to: The URL you created in Build the return_to URL
  • openid.realm: https://core-api.hiveaxyl.com, the origin of the return_to URL
  • openid.identity: http://specs.openid.net/auth/2.0/identifier_select
  • openid.claimed_id: http://specs.openid.net/auth/2.0/identifier_select

Open the web login session

Use OpenAsync() of the web login session to open the login request URL you built. In OpenRequest.RedirectUri, put the app callback URL {appId}://oauth-callback, not the relay URL.

Verify the callback

The Hive Axyl relay URL forwards the query string that Steam sent to the app callback URL without changing it. Even if the user declines Steam login, Steam does not close the window; it returns a callback whose openid.mode is cancel.

So when you receive the callback, check that the callback parameters meet all of the following conditions before you extract the login values. If any condition is not met, stop the login.

  • The value of openid.mode is id_res
  • The value of openid.return_to exactly matches the stored return_to URL
  • The value of openid.claimed_id is in the https://steamcommunity.com/openid/id/{Steam ID64} format

Extract the login values

Extract the two values to put in the login request from the callback that passed verification. The web login session does not parse the callback, so the app implements the code that extracts the values itself.

  • ProviderUserId: The Steam ID64 that follows https://steamcommunity.com/openid/id/ in openid.claimed_id
  • ProviderToken: The entire query string of the callback URL, from after ? to before #

For ProviderToken, put the query string exactly as Steam sent it, not a string reassembled from parsed parameters. The Hive Axyl authentication server sends this value to Steam to confirm the authenticity of the login result, so if the parameter order changes or the string is re-encoded, signature verification fails and login is rejected. ExtractQueryString() in the following example is code that the app implements itself to cut out the string from after ? to before # in the callback URL as is.

using System;
using Hive.Axyl.Auth.Addon.WebAuth;
using Hive.Axyl.Core;

if (!HiveCore.TryResolve<IExternalUserAgent>(out var webAuth))
{
    return;
}

const string RelayUrl         = "https://core-api.hiveaxyl.com/auth/v1/provider/callback";
const string SteamIdPrefix    = "https://steamcommunity.com/openid/id/";
const string IdentifierSelect = "http://specs.openid.net/auth/2.0/identifier_select";

string appCallback = "{appId}://oauth-callback";

// Create and store a return_to URL with a new random value for every login attempt.
string returnTo = RelayUrl
    + "?relayTo=" + Uri.EscapeDataString(appCallback)
    + "&s="       + Uri.EscapeDataString(CreateNonce());

string steamLoginUrl = "https://steamcommunity.com/openid/login"
    + "?openid.ns="         + Uri.EscapeDataString("http://specs.openid.net/auth/2.0")
    + "&openid.mode=checkid_setup"
    + "&openid.return_to="  + Uri.EscapeDataString(returnTo)
    + "&openid.realm="      + Uri.EscapeDataString("https://core-api.hiveaxyl.com")
    + "&openid.identity="   + Uri.EscapeDataString(IdentifierSelect)
    + "&openid.claimed_id=" + Uri.EscapeDataString(IdentifierSelect);

var sessionResult = await webAuth.OpenAsync(new OpenRequest {
    Url         = steamLoginUrl,
    RedirectUri = appCallback,   // The app callback URL, not the relay URL
});
if (sessionResult is not ExternalUserAgentServiceOpenResult.Success session)
{
    // For handling UserCanceled and Failure, see [Web login session](web-auth-session.md)
    return;
}

var callback = session.Data.Parameters;

callback.TryGetValue("openid.mode", out string openIdMode);
if (openIdMode != "id_res")
{
    // If "cancel", the user declined Steam login → keep the login screen
    return;
}

if (!callback.TryGetValue("openid.return_to", out string returnedTo) || returnedTo != returnTo)
{
    // Not a response started by this login → stop the login
    return;
}

if (!callback.TryGetValue("openid.claimed_id", out string claimedId)
    || !claimedId.StartsWith(SteamIdPrefix, StringComparison.Ordinal)
    || !ulong.TryParse(claimedId.Substring(SteamIdPrefix.Length), out _))
{
    // Not in the Steam ID64 format → stop the login
    return;
}

string steamProviderUserId = claimedId.Substring(SteamIdPrefix.Length);
string steamProviderToken  = ExtractQueryString(session.Data.CallbackUrl);

2. Log in with an external authentication provider

Call Log in with an external authentication provider with the steamProviderUserId and steamProviderToken you got in the previous step. Specify Provider.Steam for ProviderId.

using Hive.Axyl.Auth;
using Hive.Axyl.Core;

IAuthService auth = HiveCore.Resolve<IAuthService>();

var (codeVerifier, codeChallenge) = CreatePkce();

var result = await auth.LoginProviderAsync(new ProviderLoginRequest {
    ProviderId          = Provider.Steam,
    ProviderUserId      = steamProviderUserId,
    ProviderToken       = steamProviderToken,
    DeviceKey           = deviceKey,
    ClientId            = "{clientId}",
    CodeChallenge       = codeChallenge,
    CodeChallengeMethod = CodeChallengeMethod.S256,
});

if (result is AuthLoginProviderResult.Success success)
{
    // Login succeeded → issue tokens and activate the session.
    await StartSessionAsync(success.Data.AuthorizationCode, codeVerifier, success.Data.PlayerId);
}
// For other response cases and the full call parameters, see [Log in with an external authentication provider](provider-login.md)

On Windows and macOS, release the authentication ticket after you receive the result of this call.

CreatePkce() is a helper defined in Create a guest account. For the definition of StartSessionAsync() and the session activation procedure, see Issue tokens and activate the session.

Next steps