Nakama is a scalable Open Source game backend. It allows you to provide a number of authentication options for your players, including Steam login.
Providing Steam login can make it so that players who launch the game via Steam can create an account on your Nakama server and login - without having to do anything at all!
Implementing this in your Godot game is actually quite simple, but it's not very well documented.
Since I already put in the time to work this out for my game, Retro Tank Party, I figured I'd make a short tutorial to help anyone else who wanted to do the same.
Read more for the step-by-step instructions!
1. Configure Nakama for Steam login
First, you have to make some changes to your Nakama configuration file to enable Steam login.
This file is usually called config.yml, but you can specify the file with the --config argument when launching Nakama, so it may be called something else in your case.
It's also possible that you don't have a configuration file and are just using the defaults. If so, you'll need to create one, and make sure you're launching Nakama with the right arguments. If you're running Nakama via Docker Compose, check out the official documentation on setting up a configuration file.
In any case, you'll need to add something like the following to your configuration file:
social: steam: app_id: 1234 publisher_key: 'xxxxx'
Except you'll need to fill in app_id with the real app ID of your game, and publisher_key with a real publisher key.
To obtain a publisher key, follow the instructions on this page in Steam's documentation, under "Creating a Publisher Web API Key". Skip over the "User Key" section - that's not what you want!
Afterwards, restart Nakama for these configuration changes to take effect.
2. Setup GodotSteam
In order for your Godot game to use the Steam API, you need to be using GodotSteam.
Odds are, if you're making a Godot game for Steam, you're already using GodotSteam and initializing it in your game.
If not, here's the short version:
- You'll need to use a Steam-enabled version of the Godot editor - grab the latest release with GodotSteam in the name (skip over ones labeled GodotServer or GDNative)
- Then copy in the redistributeable library for your platform that you got with the Steamworks SDK after becoming a Steam partner
-
Finally, add some code to your game to initialize Steam. I like to do this in an autoload singleton called SteamManager. Here's a minimal example:
extends Node # Replace this with your real app ID! var steam_app_id := 1234 func _ready() -> void: if Steam.restartAppIfNecessary(steam_app_id): get_tree().quit() var init: Dictionary = Steam.steamInit(false) if init['status'] != 1: OS.alert(init['verbal'] + " (%s)" % init['status']) get_tree().quit() if not Steam.isSubscribed(): OS.alert("User does not own this game") get_tree().quit() func _process(_delta: float) -> void: Steam.run_callbacks()
That will restart the app via Steam if it was launched outside the launcher, initialize the Steam API, and then verify that the user has a license for the game. It also makes sure that the Steam callbacks will run correctly every frame.
The GodotSteam documentation is pretty good, so take a look there for more detailed information!
3. Authenticate with Nakama via Steam!
This is the part that took me a while to figure out.
The Nakama documentation says the authenticate_steam_async() method takes a Steam token, and the GodotSteam documentation says Steam.getAuthSessionTicket() returns this as binary data (a collection of bytes).
But how to encode this binary data? As base64? As a JSON string with \x00 values (since it's ultimately passed to Steam's Web API)? This isn't explained anywhere.
After much digging through both Nakama and GodotSteam's source code, and then Steam's documentation, it turns out that this answer is: as a hexidecimal string!
Here's a snippet demonstrating the full process to login to Nakama via Steam:
func steam_login(nakama_client: NakamaClient) -> NakamaSession: var auth_ticket: Dictionary = Steam.getAuthSessionTicket() # Wait for the ticket to be communicated to Steam. var result = yield(Steam, "get_auth_session_ticket_response") if result[1] != Steam.RESULT_OK: return null # Convert binary ticket to hexidecimal. # See: https://partner.steamgames.com/doc/webapi/ISteamUserAuth#AuthenticateUserTicket # Nakama uses that method to authenticate on its end. var auth_ticket_string := '' for i in range(auth_ticket['size']): auth_ticket_string += "%02x" % auth_ticket['buffer'][i] # Authenticate with Nakama. var nakama_session = yield(nakama_client.authenticate_steam_async(auth_ticket_string), 'completed') if nakama_session.is_exception(): return null return nakama_session
And that's it!
NOTE: because we're using yield() in this function, we'd need to yield() on it to get the result as well. So, if you were calling this from a button pressed signal, you'd use it like this:
func _on_LoginButton_pressed() -> void: var nakama_session = yield(steam_login(), 'completed') if nakama_session: # Success! do_something_useful_with_nakama_session(nakama_session) else: OS.alert("Unable to login via Steam")
I hope that's helpful to someone out there!
Happy Hacking :-)
Comments
Exactly what I am looking…
Exactly what I am looking for! It'll help me indeed! Thank you so much for going through all of these and posting them here :)))
That is very helpful! Thanks
That is very helpful! Thanks