Skip to main content

Steam login to Nakama using Godot

Submitted by David Snopek on Tuesday, 2021-07-06 @ 8:34am
Steam logo pointing at Nakama logo, with Godot logo between

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:

  1. 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)
  2. Then copy in the redistributeable library for your platform that you got with the Steamworks SDK after becoming a Steam partner
  3. 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 :-)

Level:
Intermediate
Topic:

Subscribe!

Subscribe to get an email when new articles or videos are posted on SnopekGames.com!

* indicates required

Comments

Add new comment
The content of this field is kept private and will not be shown publicly.

Plain text

  • No HTML tags allowed.
  • Lines and paragraphs break automatically.
  • Web page addresses and email addresses turn into links automatically.
CAPTCHA
This question is for testing whether or not you are a human visitor and to prevent automated spam submissions.