Skip to content
Joël Deffner edited this page Sep 3, 2026 · 1 revision

Auth

Since v0.5.0. steam.auth is the curated layer over ISteamUser: issue auth tickets, validate somebody else's, and read the small facts about the logged-in account. It is called auth because the generated ISteamUser class already owns steam.user.

A ticket is how a game server or a Web API backend learns that this user really is who they claim to be. getSessionTicket is the one for your own game server, which validates it with beginSession. getWebApiTicket is the one for an HTTP backend calling Valve's AuthenticateUserTicket. Both wait for Steam's confirming callback, so an awaited ticket is a usable ticket.

Three methods are async: the two ticket issuers and requestEncryptedAppTicket. Everything else is a local read or a fire-and-forget call. The Auth instance is created lazily and cached on the Steam object. Steam ids are bigint; ticket handles are 32-bit, so plain numbers.

getSessionTicket

getSessionTicket(): Promise<AuthTicket>

Issues a session ticket for your own game server. Steam fills the bytes at once and confirms them with GetAuthSessionTicketResponse_t; this awaits that confirmation through steam.once, so the resolved ticket is one a server can accept.

No identity parameter. Valve's GetAuthSessionTicket takes a SteamNetworkingIdentity * naming the peer the ticket is for. That struct carries a C union, which steamwand excludes on purpose: steam_api.json cannot describe unions, and a guessed layout would read garbage. This binding always passes null, which means "any identity". Call the generated steam.user.GetAuthSessionTicket yourself if you need to hand Steam a pointer to an identity you built by hand.

Cancel the ticket with cancelTicket when the session ends, or the handle stays allocated.

import { init } from 'steamwand.js';

const steam = init({ appId: 480 });
const ticket = await steam.auth.getSessionTicket();
// send ticket.hex to your game server, then:
steam.auth.cancelTicket(ticket.handle);
steam.close();

Throws Error: steamwand: GetAuthSessionTicket returned an invalid handle when Steam refused to issue one at all, and SteamResultError with operation: 'GetAuthSessionTicket' when the confirmation came back non-OK, for example k_EResultNoConnection on an offline client.

getWebApiTicket

getWebApiTicket(identity?: string): Promise<AuthTicket>

Issues a ticket for Valve's AuthenticateUserTicket Web API endpoint, which is what an HTTP backend needs. identity is a string you agree with that backend and Valve echoes back on verification; omit it for none.

There is no synchronous form. The bytes only exist inside the GetTicketForWebApiResponse_t callback, so the ticket is whatever that callback carried.

const ticket = await steam.auth.getWebApiTicket('my-backend');
// POST ticket.hex to ISteamUserAuth/AuthenticateUserTicket
steam.auth.cancelTicket(ticket.handle);

Throws Error: steamwand: GetAuthTicketForWebApi returned an invalid handle, or SteamResultError with operation: 'GetAuthTicketForWebApi'.

cancelTicket

cancelTicket(handle: number): void

Cancels a ticket this user issued. Every server that authenticated with it gets a ValidateAuthTicketResponse_t carrying k_EAuthSessionResponseAuthTicketCanceled. Call it when the player disconnects, and on shutdown for every ticket still out.

beginSession

beginSession(ticket: Buffer, steamId: bigint): void

Starts authenticating another user's session ticket. This is the server side of getSessionTicket.

It returns nothing and throws on any non-OK result. The answer is not here either: it arrives asynchronously as a ValidateAuthTicketResponse_t, so subscribe with onValidateTicket before calling this. Pair every successful call with endSession.

const off = steam.auth.onValidateTicket((r) => console.log(r.steamId, r.response));
steam.auth.beginSession(ticketBytes, playerSteamId);
// later: steam.auth.endSession(playerSteamId); off();

Throws Error: steamwand: BeginAuthSession failed: <name> naming the EBeginAuthSessionResult, for example k_EBeginAuthSessionResultExpiredTicket or k_EBeginAuthSessionResultDuplicateRequest. That is not an EResult, so it is not a SteamResultError.

endSession

endSession(steamId: bigint): void

Ends a session started with beginSession, for the same Steam id. Steam has no result for this, so it cannot fail from JavaScript. Skipping it leaks the session on Steam's side until the process exits.

onValidateTicket

onValidateTicket(listener: (result: ValidateTicketResult) => void): () => void

Subscribes to the answers for every session started with beginSession, and returns an unsubscribe function.

The listener runs once per answer, including later ones for a session that already validated: a ban or a cancelled ticket arrives the same way. Treat any non-OK response as a reason to drop the player.

userHasLicenseForApp

userHasLicenseForApp(steamId: bigint, appId: number): number

Whether another user owns an app, as an EUserHasLicenseForAppResult: 0 has a license, 1 does not, 2 this client may not ask. Only meaningful after beginSession succeeded for that user, which is what gives this client the right to ask.

requestEncryptedAppTicket

requestEncryptedAppTicket(data?: Buffer): Promise<Buffer>

Requests an encrypted app ticket and resolves with its bytes. data is up to 1 KB of your own data to seal into the ticket.

The ticket is decrypted on your backend with the app's encryption key from the partner site, so an app without that key configured cannot use this. Steam rate limits it to one call per minute.

Throws SteamResultError with operation: 'RequestEncryptedAppTicket', for example k_EResultNoConnection, or k_EResultLimitExceeded when called again too soon. Throws a plain Error when the ticket did not fit the 2048-byte read buffer, and SteamApiCallError when the call itself produced no usable result.

Account facts

Five local reads about the logged-in account. None of them throws.

isLoggedOn(): boolean
steamLevel(): number
isBehindNat(): boolean
isPhoneVerified(): boolean
isTwoFactorEnabled(): boolean
  • isLoggedOn is whether the client reached Valve's servers. False in offline mode, which is when the ticket methods start failing.
  • steamLevel is the profile level, or 0 while Steam does not know it yet.
  • isBehindNat is whether Steam detected a NAT in front of this user, which matters for peer to peer connectivity.
  • isPhoneVerified and isTwoFactorEnabled are the account's phone verification and Steam Guard mobile authenticator.

Types

AuthTicket

Returned by getSessionTicket and getWebApiTicket.

Field Type Meaning
handle number Ticket handle, for cancelTicket. 32-bit.
ticket Buffer The raw bytes, exactly as long as Steam reported.
hex string The same bytes as lowercase hex, which is what Valve's Web API expects.

ValidateTicketResult

Handed to an onValidateTicket listener.

Field Type Meaning
steamId bigint Steam id the ticket belongs to.
response number EAuthSessionResponse. 0 means the session is authenticated.
ownerSteamId bigint Steam id that owns the license, which differs from steamId under Family Sharing.

Errors

Shape When
Error: steamwand: GetAuthSessionTicket returned an invalid handle Steam refused to issue a session ticket at all.
Error: steamwand: GetAuthTicketForWebApi returned an invalid handle The same for a Web API ticket.
Error: steamwand: BeginAuthSession failed: <EBeginAuthSessionResult name> The ticket was rejected outright: expired, invalid, a duplicate request, or a game-mismatch. Not an EResult.
SteamResultError A ticket confirmation or RequestEncryptedAppTicket came back with a non-OK EResult. operation and result are on the error.
Error: steamwand: GetEncryptedAppTicket returned false (...) The encrypted ticket did not fit the read buffer.
SteamApiCallError RequestEncryptedAppTicket never produced a usable result. See How It Works.

cancelTicket, endSession and the five boolean reads have no failure path, because Steam returns nothing that can say so.

What this layer does not do

The rest of ISteamUser is on the raw generated steam.user:

  • GetSteamID, which the Steam object already exposes as steam.steamId().
  • GetHSteamUser, the raw user handle the flat API passes around, and GetUserDataFolder.
  • AdvertiseGame, which tells Steam which server this user joined.
  • The voice API: StartVoiceRecording, StopVoiceRecording, GetAvailableVoice, GetVoice, DecompressVoice, GetVoiceOptimalSampleRate.
  • GetGameBadgeLevel, RequestStoreAuthURL, GetMarketEligibility, and the phone checks BIsPhoneIdentifying and BIsPhoneRequiringVerification.
  • GetDurationControl and BSetDurationControlOnlineState, the China anti-addiction hours.

Flat API explains the calling convention.

Next: System for the machine and client facts, or Core API for steam.once, which is how the ticket methods wait.

Clone this wiki locally