Authentication #

The server has built-in authentication so clients can only send requests and connect if they have the server key. The default server key is defaultkey but it is very important to set a unique value. This value should be embedded within client code.

When authentication is successful a client can create a session as a user.

Client
1
2
var useSSL = false;
var client = new nakamajs.Client("defaultkey", "127.0.0.1", 7350, useSSL);
Client
1
2
// Use "https" scheme if you've setup SSL.
var client = new Client("http", "127.0.0.1", 7350, "defaultkey");
Client
1
2
3
4
5
NClientParameters parameters;
parameters.serverKey = "defaultkey";
parameters.host = "127.0.0.1";
parameters.port = DEFAULT_PORT;
NClientPtr client = createDefaultClient(parameters);
Client
1
2
3
Client client = new DefaultClient("defaultkey", "127.0.0.1", 7349, false)
// or same as above.
Client client = DefaultClient.defaults("defaultkey");
Client
1
onready var client := Nakama.create_client("defaultkey", "127.0.0.1", 7350, "http")
Client
1
@onready var client := Nakama.create_client("defaultkey", "127.0.0.1", 7350, "http")
Client
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
local defold = require "nakama.engine.defold"

local config = {}
config.host = 127.0.0.1
config.port = 7350
config.use_ssl = false
config.username = "defaultkey"
config.engine = defold

local client = nakama.create_client(config)
Client
1
let client = GrpcClient(serverKey: "defaultkey", trace: true)
Client
1
2
3
4
5
final client = getNakamaClient(
  host: '127.0.0.1',
  ssl: false,
  serverKey: 'defaultkey',
);

Every user account is created from one of the options used to authenticate. We call each of these options a “link” because it’s a way to access the user’s account. You can add more than one link to each account which is useful to enable users to login in multiple ways across different devices.

Authenticate #

Before you interact with the server, you must obtain a session token by authenticating with the system. The authentication system is very flexible. You could register a user with an email address, link their Facebook account, and use it to login from another device.

By default the system will create a user automatically if the identifier used to authenticate did not previously exist in the system. This pattern is shown in the device section.

For full examples on the best way to handle registering and login in each of the clients have a look at their guides.

Device #

A device identifier can be used as a way to unobtrusively register a user with the server. This offers a frictionless user experience but can be unreliable because device identifiers can sometimes change in device updates.

You can choose a custom username when creating the account. To do this, set username to a custom name. If you want to only authenticate without implicitly creating a user account, set create to false.

A device identifier must contain alphanumeric characters with dashes and be between 10 and 128 bytes.

Client
1
2
3
curl "http://127.0.0.1:7350/v2/account/authenticate/device?create=true&username=mycustomusername" \
  --user 'defaultkey:' \
  --data '{"id":"uniqueidentifier"}'
Client
1
2
3
4
5
6
7
8
POST /v2/account/authenticate/device?create=true&username=mycustomusername
Host: 127.0.0.1:7350
Accept: application/json
Content-Type: application/json
Authorization: Basic base64(ServerKey:)
{
  "id": "uniqueidentifier"
}
Client
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// This import is only required with React Native
var deviceInfo = require('react-native-device-info');
var deviceId = null;

try {
  const value = await AsyncStorage.getItem('@MyApp:deviceKey');

  if (value !== null){
    deviceId = value
  }
  else {
    deviceId = deviceInfo.getUniqueID();

    AsyncStorage.setItem('@MyApp:deviceKey', deviceId).catch(function(error){
      console.log("An error occurred: %o", error);
    });
  }
}
catch (error) {
  console.log("An error occurred: %o", error);
}

var create = true;
const session = await client.authenticateDevice(deviceId, create, "mycustomusername");
console.info("Successfully authenticated:", session);
Client
1
2
3
4
// Should use a platform API to obtain a device identifier.
var deviceId = System.Guid.NewGuid().ToString();
var session = await client.AuthenticateDeviceAsync(deviceId);
System.Console.WriteLine("New user: {0}, {1}", session.Created, session);
Client
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
auto loginFailedCallback = [](const NError& error)
{
};

auto loginSucceededCallback = [](NSessionPtr session)
{
    cout << "Successfully authenticated" << endl;
};

std::string deviceId = "unique device id";

client->authenticateDevice(deviceId, opt::nullopt, opt::nullopt, {}, loginSucceededCallback, loginFailedCallback);
Client
1
2
3
String id = UUID.randomUUID().toString();
Session session = client.authenticateDevice(id).get();
System.out.format("Session: %s ", session.getAuthToken());
Client
1
2
3
4
5
6
7
8
9
# Unique ID is not supported by Godot in HTML5, use a different way to generate an id, or a different authentication option.
var deviceid = OS.get_unique_id()
var session : NakamaSession = yield(client.authenticate_device_async(deviceid), "completed")

if session.is_exception():
    print("An error occurred: %s" % session)
    return

print("Successfully authenticated: %s" % session)
Client
1
2
3
4
5
6
7
8
9
# Unique ID is not supported by Godot in HTML5, use a different way to generate an id, or a different authentication option.
var deviceid = OS.get_unique_id()
var session : NakamaSession = await client.authenticate_device_async(deviceid)

if session.is_exception():
    print("An error occurred: %s" % session)
    return

print("Successfully authenticated: %s" % session)
Client
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
-- login using the token and create an account if the user
-- doesn't already exist
local result = client.authenticate_device(defold,uuid(), nil, true, "mycustomusername")

if not result.token then
  print("Unable to login")
end

-- store the token and use it when communicating with the server
client.set_bearer_token(result.token)
Client
1
2
3
4
5
6
7
8
guard let deviceId = await UIDevice.current.identifierForVendor?.uuidString else { return }

do {
    let session = try await client.authenticateDevice(id: deviceId, create: create, username: "mycustomusername")
    print("Successfully authenticated:", session)
} catch {
    debugPrint(error)
}
Client
1
2
// You can obtain device id for multiplatforms using a package like `device_info_plus`
final session = await client.authenticateDevice(deviceId: '<obtained_device_id>');

In games it is often a better option to use Google or Game Center to unobtrusively register the user.

Email #

Users can be registered with an email and password. The password is hashed before it’s stored in the database server and cannot be read or “recovered” by administrators. This protects a user’s privacy.

You can choose a custom username when creating the account. To do this, set username to a custom name. If you want to only authenticate without implicitly creating a user account, set create to false.

An email address must be valid as defined by RFC-5322 and passwords must be at least 8 characters.

Client
1
2
3
curl "http://127.0.0.1:7350/v2/account/authenticate/email?create=true&username=mycustomusername" \
  --user 'defaultkey:' \
  --data '{"email":"email@example.com", "password": "3bc8f72e95a9"}'
Client
1
2
3
4
5
6
7
8
9
POST /v2/account/authenticate/email?create=true&username=mycustomusername
Host: 127.0.0.1:7350
Accept: application/json
Content-Type: application/json
Authorization: Basic base64(ServerKey:)
{
  "email": "email@example.com",
  "password": "3bc8f72e95a9"
}
Client
1
2
3
4
5
const email = "email@example.com";
const password = "3bc8f72e95a9";
const create = true;
const session = await client.authenticateEmail(email, password, create, "mycustomusername");
console.info("Successfully authenticated:", session);
Client
1
2
3
4
const string email = "email@example.com";
const string password = "3bc8f72e95a9";
var session = await client.AuthenticateEmailAsync(email, password);
System.Console.WriteLine("New user: {0}, {1}", session.Created, session);
Client
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
auto successCallback = [](NSessionPtr session)
{
    std::cout << "Authenticated successfully. User ID: " << session->getUserId() << std::endl;
};

auto errorCallback = [](const NError& error)
{
};

string email = "email@example.com";
string password = "3bc8f72e95a9";
string username = "mycustomusername";
bool create = true;
client->authenticateEmail(email, password, username, create, {}, successCallback, errorCallback);
Client
1
2
3
4
String email = "email@example.com";
String password = "3bc8f72e95a9";
Session session = client.authenticateEmail(email, password).get();
System.out.format("Session: %s ", session.getAuthToken());
Client
1
2
3
4
5
6
7
8
9
var email = "email@example.com"
var password = "3bc8f72e95a9"
var session : NakamaSession = yield(client.authenticate_email_async(email, password, "mycustomusername", true), "completed")

if session.is_exception():
    print("An error occurred: %s" % session)
    return

print("Successfully authenticated: %s" % session)
Client
1
2
3
4
5
6
7
8
9
var email = "email@example.com"
var password = "3bc8f72e95a9"
var session : NakamaSession = await client.authenticate_email_async(email, password, "mycustomusername", true)

if session.is_exception():
    print("An error occurred: %s" % session)
    return

print("Successfully authenticated: %s" % session)
Client
1
2
3
4
5
6
7
8
local result = client.authenticate_email("email@example.com", "3bc8f72e95a9", nil, true, "mycustomusername")

if not result.token then
  print("Unable to login")
end

-- store the token and use it when communicating with the server
client.set_bearer_token(result.token)
Client
1
2
3
4
5
6
do {
    let session = try await client.authenticateEmail(email: "email", password: "password", create: true, username: "mycustomusername")
    print("Successfully authenticated:", session)
} catch {
    debugPrint(error)
}
Client
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
try {
  session = await client.authenticateEmail(
    email: 'email',
    password: 'password',
    create: true,
    username: 'mycustomusername',
  );
  print('Successfully authenticated: $session');
} catch (error) {
  print(error);
}

Console #

Nakama supports console authentication for all major platforms, including Nintendo Switch, Xbox One and Series X|S, and PlayStation 4/5.

Requesting Access
Console authentication is only available to developers verified by the respective console platform providers (Sony, Microsoft, Nintendo). To request access, please contact us.

The console authentication flow is similar to the device authentication flow, but requires a console identifier and a console user identifier.

Note that the examples below are only meant to be illustrative. Complete documentation can only be provided following your verification by the console platform provider(s).

Client
1
2
3
4
5
6
7
8
// Xbox authentication
var session = await client.AuthenticateCustomAsync("xbox|<xbox_code>");

// PlayStation authentication
var session = await client.AuthenticateCustomAsync("psn|<<psn_code>>");

// Nintendo authentication
var session = await client.AuthenticateCustomAsync("nintendo|<<nintendo_code>>");
Client
1
2
3
4
5
6
7
8
// Xbox authentication
client->authenticateCustom("xbox|<xbox_code>", {}, successCallback, errorCallback);

// PlayStation authentication
client->authenticateCustom("psn|<<psn_code>>", {}, successCallback, errorCallback);

// Nintendo authentication
client->authenticateCustom("nintendo|<<nintendo_code>>", {}, successCallback, errorCallback);

Code snippet for this language Defold has not been found. Please choose another language to show equivalent examples.
Code snippet for this language cURL has not been found. Please choose another language to show equivalent examples.
Code snippet for this language REST has not been found. Please choose another language to show equivalent examples.
Code snippet for this language JavaScript/Cocos2d-js has not been found. Please choose another language to show equivalent examples.
Code snippet for this language Java/Android has not been found. Please choose another language to show equivalent examples.
Code snippet for this language Godot 3 has not been found. Please choose another language to show equivalent examples.
Code snippet for this language Godot 4 has not been found. Please choose another language to show equivalent examples.

Social providers #

The server supports a lot of different social services with register and login. With each provider the user account will be fetched from the social service and used to setup the user. In some cases a user’s friends will also be fetched and added to their friends list.

To register or login as a user with any of the providers an OAuth or access token must be obtained from that social service.

Apple #

Follow the Apple Developer documentation for integrating Sign in with Apple in your applications.

You can choose a custom username when creating the account. To do this, set username to a custom name. If you want to only authenticate without implicitly creating a user account, set create to false.

Client
1
2
3
curl "http://127.0.0.1:7350/v2/account/authenticate/apple?create=true&username=mycustomusername" \
  --user 'defaultkey:' \
  --data '{"token":"..."}'
Client
1
2
3
4
5
6
7
8
POST /v2/account/authenticate/apple?create=true&username=mycustomusername
Host: 127.0.0.1:7350
Accept: application/json
Content-Type: application/json
Authorization: Basic base64(ServerKey:)
{
  "token": "...",
}
Client
1
2
3
4
5
const token = "...";
const create = true;
const username = "...";
const session = await client.authenticateApple(token, create, username);
console.info("Successfully authenticated: %o", session);
Client
1
2
3
4
5
var username = "...";
var token = "...";

var session = await client.AuthenticateAppleAsync(token, username);
System.Console.WriteLine("New user: {0}, {1}", session.Created, session);
Client
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
auto successCallback = [](NSessionPtr session)
{
    std::cout << "Authenticated successfully. User ID: " << session->getUserId() << std::endl;
};

auto errorCallback = [](const NError& error)
{
};

std::string username = "...";
std::string token = "...";

client->authenticateApple(token, username);
Client
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
var username = "..."
var token = "..."

var session : NakamaSession = yield(client.authenticate_apple_async(token, username), "completed")

if session.is_exception():
    print("An error occurred: %s" % session)
    return

print("Successfully authenticated: %s" % session)
Client
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
var username = "..."
var token = "..."

var session : NakamaSession = await client.authenticate_apple_async(token, username)

if session.is_exception():
    print("An error occurred: %s" % session)
    return

print("Successfully authenticated: %s" % session)

{

Client
1
2
3
String token = "...";
Session session = client.authenticateApple(token).get();
System.out.format("Session %s", session.getAuthToken());

Client
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
-- Use https://defold.com/assets/siwa/
local token = "..."
local username = "..."
local result = client.authenticate_apple(token, username)

if not result.token then
  print("Unable to login")
end

-- store the token and use it when communicating with the server
client.set_bearer_token(result.token)
Client
1
2
3
4
5
6
7
8
9
let oauthToken = "<token>"
var username = "..."

do {
    let session = try await client.authenticateApple(oauthToken: oauthToken, username: "mycustomusername")
    print("Successfully authenticated:", session)
} catch {
    debugPrint(error)
}
Client
1
2
3
4
5
6
7
final oauthToken = '<token>';
final username = '...';

final session = await client.authenticateApple(
  token: oauthToken,
  username: 'mycustomusername',
);

Facebook #

With Facebook you’ll need to add the Facebook SDK to your project which can be downloaded online. Follow their guides on how to integrate the code. With a mobile project you’ll also need to complete instructions on how to configure iOS and Android.

You can choose a custom username when creating the account. To do this, set username to a custom name. If you want to only authenticate without implicitly creating a user account, set create to false.

When authenticating via Facebook, the following profile fields are fetched and stored in the user account:

  • ID
  • Name
  • Email
  • Photo

Additionally, you can optionally import Facebook friends into Nakama’s friend graph when authenticating. To do this, set import to true.

Client
1
2
3
curl "http://127.0.0.1:7350/v2/account/authenticate/facebook?create=true&username=mycustomusername&import=true" \
    --user 'defaultkey:' \
    --data '{"token":"valid-oauth-token"}' # Supports the use of both OAuth and Facebook Limited Login (JWT) tokens.
Client
1
2
3
4
5
6
7
8
POST /v2/account/authenticate/facebook?create=true&username=mycustomusername&import=true
Host: 127.0.0.1:7350
Accept: application/json
Content-Type: application/json
Authorization: Basic base64(ServerKey:)
{
  "token": "...",
}
Client
1
2
3
4
const oauthToken = "...";
const import = true;
const session = await client.authenticateFacebook(oauthToken, true, "mycustomusername", import);
console.log("Successfully authenticated:", session);
Client
1
2
3
const string oauthToken = "...";
var session = await client.AuthenticateFacebookAsync(oauthToken);
System.Console.WriteLine("New user: {0}, {1}", session.Created, session);
Client
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
auto loginFailedCallback = [](const NError& error)
{
};

auto loginSucceededCallback = [](NSessionPtr session)
{
    cout << "Authenticated successfully. User ID: " << session->getUserId() << endl;
};

std::string oauthToken = "...";
bool importFriends = true;
client->authenticateFacebook(oauthToken, "mycustomusername", true, importFriends, {}, loginSucceededCallback, loginFailedCallback);
Client
1
2
3
String oauthToken = "...";
Session session = client.authenticateFacebook(oauthToken).get();
System.out.format("Session %s", session.getAuthToken());
Client
1
2
3
4
5
6
7
8
var oauth_token = "..."
var session : NakamaSession = yield(client.authenticate_facebook_async(oauth_token), "completed")

if session.is_exception():
    print("An error occurred: %s" % session)
    return

print("Successfully authenticated: %s" % session)
Client
1
2
3
4
5
6
7
8
var oauth_token = "..."
var session : NakamaSession = await client.authenticate_facebook_async(oauth_token)

if session.is_exception():
    print("An error occurred: %s" % session)
    return

print("Successfully authenticated: %s" % session)
Client
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
-- Use the official Defold Facebook integration (www.defold.com/extension-facebook)
local permissions = { "public_profile" }
-- login using read permissions
-- there is no need to specify a publishing audience when requesting read permissions
facebook.login_with_permissions(permissions, facebook.AUDIENCE_NONE, function(self, data)
  local result = client.authenticate_facebook(facebook.access_token(), nil, true, "mycustomusername")

  if not result.token then
    print("Unable to login")
    return
  end
  -- store the token and use it when communicating with the server
  client.set_bearer_token(result.token)
end)
Client
1
2
3
4
5
6
7
8
9
let oauthToken = "<token>"
var importFriends = true

do {
    let session = try await client.authenticateFacebook(accessToken: oauthToken, create: true, username: "mycustomusername", importFriends: importFriends)
    print("Successfully authenticated:", session)
} catch {
    debugPrint(error)
}
Client
1
2
3
4
5
6
7
8
9
final oauthToken = '<token>';
final importFriends = true;

final session = await client.authenticateFacebook(
  token: oauthToken,
  create: true,
  username: 'mycustomusername',
  importFriends: importFriends,
);

Facebook Instant #

Ensure that you’ve configured your FB Instant App secret for Nakama and initialized the Facebook Instant Games SDK using FBInstant.initializeAsync().

Code snippet for this language .NET/Unity has not been found. Please choose another language to show equivalent examples.
Code snippet for this language C++/Unreal/Cocos2d-x has not been found. Please choose another language to show equivalent examples.

Client
1
2
3
curl "http://127.0.0.1:7350/v2/account/authenticate/facebookinstantgame?create=true&username=mycustomusername" \
    --user 'defaultkey:' \
    --data '{"token":"valid-oauth-token"}' # Supports the use of both OAuth and Facebook Limited Login (JWT) tokens.
Client
1
2
3
const result = await FBInstant.player.getSignedPlayerInfoAsync();
var session = await client.authenticateFacebookInstantGame(result.getSignature());
console.info("Successfully authenticated: %o", session);
Client
1
2
3
String accessToken = "...";
Session session = client.authenticateFacebookInstant(accessToken).get();
System.out.format("Session %s", session.getAuthToken());
Client
1
2
3
4
5
6
7
8
var signed_player_info = "..."
var session : NakamaSession = yield(client.authenticate_facebook_instant_game_async(signed_player_info), "completed")

if session.is_exception():
    print("An error occurred: %s" % session)
    return

print("Successfully authenticated: %s" % session)
Client
1
2
3
4
5
6
7
8
var signed_player_info = "..."
var session : NakamaSession = await client.authenticate_facebook_instant_game_async(signed_player_info)

if session.is_exception():
    print("An error occurred: %s" % session)
    return

print("Successfully authenticated: %s" % session)
Client
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
-- Use the official Defold Facebook Instant Games integration (www.defold.com/extension-fbinstant)
fbinstant.get_signed_player_info("developer payload", function(self, signature)
  local result = client.authenticate_facebook_instant_game(signature, nil, true, "mycustomusername")

  if not result.token then
    print("Unable to login")
    return
  end
  -- store the token and use it when communicating with the server
  client.set_bearer_token(result.token)
end)
Client
1
2
3
4
5
6
7
8
let token = "<token>"

do {
    let session = try await client.authenticateFacebookInstantGame(token: token, create: true, username: "mycustomusername")
    print("Successfully authenticated:", session)
} catch {
    debugPrint(error)
}
Client
1
2
3
4
5
6
7
final token = '<token>';

final session = await client.authenticateFacebookInstantGame(
  signedPlayerInfo: token,
  create: true,
  username: 'mycustomusername',
);

Google #

Similar to Facebook, for registration and login you should use one of Google’s client SDKs.

Google Play Games Plugin >=v0.11.x

For Google Play Games Plugin v0.11.x or greater, you must use Server-Side Access to Google Play Games Services. To enable this behavior in Nakama you must obtain credentials that include scopes to access Players:get endpoint.

Nakama is configured by setting the flag google_auth.credentials_json.

You can choose a custom username when creating the account. To do this, set username to a custom name. If you want to only authenticate without implicitly creating a user account, set create to false.

Client
1
2
3
curl "http://127.0.0.1:7350/v2/account/authenticate/google?create=true&username=mycustomusername" \
  --user 'defaultkey:' \
  --data '{"token":"valid-oauth-token"}'
Client
1
2
3
4
5
6
7
8
POST /v2/account/authenticate/google?create=true&username=mycustomusername
Host: 127.0.0.1:7350
Accept: application/json
Content-Type: application/json
Authorization: Basic base64(ServerKey:)
{
  "token": "...",
}
Client
1
2
3
4
const playerIdToken = "...";
const create = true;
const session = await client.authenticateGoogle(oauthToken, create, "mycustomusername");
console.info("Successfully authenticated: %o", session);
Client
1
2
3
const string playerIdToken = "...";
var session = await client.AuthenticateGoogleAsync(playerIdToken);
System.Console.WriteLine("New user: {0}, {1}", session.Created, session);
Client
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
auto successCallback = [](NSessionPtr session)
{
    std::cout << "Authenticated successfully. User ID: " << session->getUserId() << std::endl;
};

auto errorCallback = [](const NError& error)
{
};

string oauthToken = "...";
client->authenticateGoogle(oauthToken, "mycustomusername", true, {}, successCallback, errorCallback);
Client
1
2
3
String accessToken = "...";
Session session = client.authenticateGoogle(accessToken).get();
System.out.format("Session %s", session.getAuthToken());
Client
1
2
3
4
5
6
7
8
var oauth_token = "..."
var session : NakamaSession = yield(client.authenticate_google_async(oauth_token), "completed")

if session.is_exception():
    print("An error occurred: %s" % session)
    return

print("Successfully authenticated: %s" % session)
Client
1
2
3
4
5
6
7
8
var oauth_token = "..."
var session : NakamaSession = await client.authenticate_google_async(oauth_token)

if session.is_exception():
    print("An error occurred: %s" % session)
    return

print("Successfully authenticated: %s" % session)
Client
1
2
3
4
5
6
7
8
local result = client.authenticate_google(oauth_token, nil, true, "mycustomusername")

if not result.token then
  print("Unable to login")
end

-- store the token and use it when communicating with the server
client.set_bearer_token(result.token)

Game Center #

Apple devices have built-in authentication which can be done without user interaction through Game Center. The register or login process is a little complicated because of how Apple’s services work.

You can choose a custom username when creating the account. To do this, set username to a custom name. If you want to only authenticate without implicitly creating a user account, set create to false.

Client
1
2
3
4
5
6
7
8
String playerId = "...";
String bundleId = "...";
Long timestampSeconds = <...>;
String salt = "...";
String signature = "...";
String publicKeyUrl = "...";
Session session = client.authenticateGameCenter(playerId, bundleId, timestampSeconds, salt, signature, publicKeyUrl).get();
System.out.format("Session %s", session.getAuthToken());
Client
1
2
3
curl "http://127.0.0.1:7350/v2/account/authenticate/gamecenter?create=true&username=mycustomusername" \
  --user 'defaultkey:' \
  --data '{"player_id":"...", "bundle_id":"...", "timestamp_seconds":0, "salt":"...", "public_key_url":"..."}'
Client
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
POST /v2/account/authenticate/gamecenter?create=true&username=mycustomusername
Host: 127.0.0.1:7350
Accept: application/json
Content-Type: application/json
Authorization: Basic base64(ServerKey:)
{
  "player_id": "...",
  "bundle_id": "...",
  "timestamp_seconds": 0,
  "salt": "...",
  "signature": "...",
  "public_key_url": "..."
}
Client
1
2
3
4
5
6
7
8
9
var bundleId = "...";
var playerId = "...";
var publicKeyUrl = "...";
var salt = "...";
var signature = "...";
var timestamp = "...";
var session = await client.AuthenticateGameCenterAsync(bundleId, playerId,
    publicKeyUrl, salt, signature, timestamp);
System.Console.WriteLine("New user: {0}, {1}", session.Created, session);
Client
1
2
3
4
5
6
7
8
9
const bundleId = "...";
const playerId = "...";
const publicKeyUrl = "...";
const salt = "...";
const signature = "...";
const timestamp = "...";
const session = await client.authenticateGameCenter(bundleId, playerId,
    publicKeyUrl, salt, signature, timestamp);
console.info("Successfully authenticated: %o", session);
Client
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
auto successCallback = [](NSessionPtr session)
{
    std::cout << "Authenticated successfully. User ID: " << session->getUserId() << std::endl;
};

auto errorCallback = [](const NError& error)
{
};

std::string playerId = "...";
std::string    bundleId = "...";
NTimestamp timestampSeconds = "...";
std::string salt = "...";
std::string signature = "...";
std::string publicKeyUrl = "...";

client->authenticateGameCenter(playerId, bundleId, timestampSeconds, salt, signature, publicKeyUrl, "mycustomusername", true, {}, successCallback, errorCallback);
Client
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
var bundle_id = "..."
var player_id = "..."
var public_key_url = "..."
var salt = "..."
var signature = "..."
var timestamp = "..."
var session : NakamaSession = yield(client.authenticate_game_center_async(bundle_id, player_id, public_key_url, salt, signature, timestamp), "completed")

if session.is_exception():
    print("An error occurred: %s" % session)
    return

print("Successfully authenticated: %s" % session)
Client
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
var bundle_id = "..."
var player_id = "..."
var public_key_url = "..."
var salt = "..."
var signature = "..."
var timestamp = "..."
var session : NakamaSession = await client.authenticate_game_center_async(bundle_id, player_id, public_key_url, salt, signature, timestamp)

if session.is_exception():
    print("An error occurred: %s" % session)
    return

print("Successfully authenticated: %s" % session)
Client
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
-- Use https://defold.com/assets/gamekit/
local bundle_id = "..."
local player_id = "..."
local public_key_url = "..."
local salt = "..."
local signature = "..."
local timestamp_seconds = 0
local result = client.authenticate_game_center(bundle_id, player_id, public_key_url, salt, signature, timestamp_seconds, nil, true, "mycustomusername")

if not result.token then
  print("Unable to login")
end

-- store the token and use it when communicating with the server
client.set_bearer_token(result.token)
Client
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
let playerId = "<playerId>"
var bundleId = "<bundleId>"
var timestampSeconds = <timestampSeconds>
var salt = "<salt>"
var signature = "<signature>"
var publicKeyUrl = "<publicKeyUrl>"
var create = true

do {
    let session = try await client.authenticateGameCenter(playerId: playerId, bundleId: bundleId, timestampSeconds: timestampSeconds, salt: salt, signature: signature, publicKeyUrl: publicKeyUrl, create: create, username: "mycustomusername")
    print("Successfully authenticated:", session)
} catch {
    debugPrint(error)
}
Client
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
final playerId = '<playerId>';
final bundleId = '<bundleId>';
final timestampSeconds = DateTime.now().millisecondsSinceEpoch ~/ 1000;
final salt = '<salt>';
final signature = '<signature>';
final publicKeyUrl = '<publicKeyUrl>';
final create = true;

final session = await client.authenticateGameCenter(
  playerId: playerId,
  bundleId: bundleId,
  timestampSeconds: timestampSeconds,
  salt: salt,
  signature: signature,
  publicKeyUrl: publicKeyUrl,
  create: create,
  username: 'mycustomusername',
);

Steam #

Steam requires you to configure the server before you can register a user. Have a look at the configuration section for what settings you need for the server.

You can choose a custom username when creating the account. To do this, set username to a custom name. If you want to only authenticate without implicitly creating a user account, set create to false.

You can optionally import Steam friends into Nakama’s friend graph when authenticating. To do this, set import to true.

Client
1
2
3
curl "http://127.0.0.1:7350/v2/account/authenticate/steam?create=true&username=mycustomusername&import=true" \
  --user 'defaultkey:' \
  --data '{"token":"valid-steam-token"}'
Client
1
2
3
4
5
6
7
8
POST /v2/account/authenticate/steam?create=true&username=mycustomusername&import=true
Host: 127.0.0.1:7350
Accept: application/json
Content-Type: application/json
Authorization: Basic base64(ServerKey:)
{
  "token": "...",
}
Client
1
2
3
4
5
6
const token = "...";
const create = true;
const username = "...";
const sync = true;
const session = await client.authenticateSteam(token, create, username, sync);
console.info("Successfully authenticated: %o", session);
Client
1
2
3
4
const string token = "...";
const bool importFriends = true;
var session = await client.AuthenticateSteamAsync(token, importFriends);
System.Console.WriteLine("New user: {0}, {1}", session.Created, session);
Client
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
auto successCallback = [](NSessionPtr session)
{
    std::cout << "Authenticated successfully. User ID: " << session->getUserId() << std::endl;
};

auto errorCallback = [](const NError& error)
{
};

string token = "...";
string username = "mycustomusername";
bool create = true;
bool importFriends = true;
client->authenticateSteam(token, username, create, importFriends, {}, successCallback, errorCallback);
Client
1
2
3
4
String token = "...";
Bool importFriends = true;
Session session = client.authenticateSteam(token, importFriends).get();
System.out.format("Session %s", session.getAuthToken());
Client
1
2
3
4
5
6
7
8
9
var steam_token = "..."
var import_friends = true
var session : NakamaSession = yield(client.authenticate_steam_async(steam_token, import_friends), "completed")

if session.is_exception():
    print("An error occurred: %s" % session)
    return

print("Successfully authenticated: %s" % session)
Client
1
2
3
4
5
6
7
8
9
var steam_token = "..."
var import_friends = true
var session : NakamaSession = await client.authenticate_steam_async(steam_token, import_friends)

if session.is_exception():
    print("An error occurred: %s" % session)
    return

print("Successfully authenticated: %s" % session)
Client
1
2
3
4
5
6
7
8
9
-- Use https://defold.com/assets/steamworks/
local result = client.authenticate_steam(steam_token, nil, true, "mycustomusername")

if not result.token then
  print("Unable to login")
end

-- store the token and use it when communicating with the server
client.set_bearer_token(result.token)
Client
1
2
3
4
5
6
7
8
9
let token = "<token>"
var create = true

do {
    let session = try await client.authenticateSteam(accessToken: token, create: create, username: "mycustomusername")
    print("Successfully authenticated:", session)
} catch {
    debugPrint(error)
}
Client
1
2
3
4
5
6
7
8
final token = '<token>';
final create = true;

final session = await client.authenticateSteam(
  token: token,
  create: create,
  username: 'mycustomusername',
);

Custom #

A custom identifier can be used in a similar way to a device identifier to login or register a user. This option should be used if you have an external or custom user identity service which you want to use. For example EA’s Origin service handles accounts which have their own user IDs.

A custom identifier must contain alphanumeric characters with dashes and be between 6 and 128 bytes.

You can choose a custom username when creating the account. To do this, set username to a custom name. If you want to only authenticate without implicitly creating a user account, set create to false.

Client
1
2
3
curl "http://127.0.0.1:7350/v2/account/authenticate/custom?create=true&username=mycustomusername" \
  --user 'defaultkey:' \
  --data '{"id":"some-custom-id"}'
Client
1
2
3
4
5
6
7
8
POST /v2/account/authenticate/custom?create=true&username=mycustomusername
Host: 127.0.0.1:7350
Accept: application/json
Content-Type: application/json
Authorization: Basic base64(ServerKey:)
{
  "id": "some-custom-id",
}
Client
1
2
3
4
const customId = "some-custom-id";
const create = true;
const session = await client.authenticateCustom(customId, create, "mycustomusername");
console.info("Successfully authenticated:", session);
Client
1
2
3
const string customId = "some-custom-id";
var session = await client.AuthenticateCustomAsync(customId);
System.Console.WriteLine("New user: {0}, {1}", session.Created, session);
Client
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
auto successCallback = [](NSessionPtr session)
{
    std::cout << "Authenticated successfully. User ID: " << session->getUserId() << std::endl;
};

auto errorCallback = [](const NError& error)
{
};

string id = "some-custom-id";
string username = "mycustomusername";
bool create = true;
client->authenticateCustom(id, username, create, {}, successCallback, errorCallback);
Client
1
2
3
String customId = "some-custom-id";
Session session = client.authenticateCustom(customId).get();
System.out.format("Session %s", session.getAuthToken());
Client
1
2
3
4
5
6
7
8
var custom_id = "some-custom-id"
var session : NakamaSession = yield(client.authenticate_custom_async(custom_id), "completed")

if session.is_exception():
    print("An error occurred: %s" % session)
    return

print("Successfully authenticated: %s" % session)
Client
1
2
3
4
5
6
7
8
var custom_id = "some-custom-id"
var session : NakamaSession = await client.authenticate_custom_async(custom_id)

if session.is_exception():
    print("An error occurred: %s" % session)
    return

print("Successfully authenticated: %s" % session)
Client
1
2
3
4
5
6
7
8
local result = client.authenticate_custom(custom_id, nil, true, "mycustomusername")

if not result.token then
  print("Unable to login")
end

-- store the token and use it when communicating with the server
client.set_bearer_token(result.token)
Client
1
2
3
4
5
6
7
8
9
let id = "<customId>"
var create = true

do {
    let session = try await client.authenticateCustom(id: id, create: create, username: "mycustomusername")
    print("Successfully authenticated:", session)
} catch {
    debugPrint(error)
}
Client
1
2
3
4
5
6
7
8
final id = '<customId>';
final create = true;

final session = await client.authenticateCustom(
  id: id,
  create: create,
  username: 'mycustomusername',
);

Session #

When an authentication call succeeds, the server responds with a session object. The session object contains at least the following:

  • The user ID
  • The username
  • A set of variables cached in the token
  • The creation time
  • The expiration time

Once the client obtains the session object, you can utilize Nakama’s real-time features such as multiplayer, notifications and status updates, passing stream data or real-time chat.

Client
1
2
3
var socket = client.createSocket();
session = await socket.connect(session);
console.info("Socket connected.");
Client
1
2
3
var socket = Socket.From(client);
await socket.ConnectAsync(session);
System.Console.WriteLine("Socket connected.");
Client
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
int port = 7350; // different port to the main API port
bool createStatus = true; // if the server should show the user as online to others.
// define real-time client in your class as NRtClientPtr rtClient;
rtClient = client->createRtClient(port);
// define listener in your class as NRtDefaultClientListener listener;
listener.setConnectCallback([]()
{
    cout << "Socket connected." << endl;
});

rtClient->setListener(&listener);
rtClient->connect(session, createStatus);
Client
1
2
SocketClient socket = client.createSocket();
socket.connect(session, new AbstractSocketListener() {}).get();
Client
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# Make this a node variable, or it will disconnect when the function that creates it returns.
onready var socket := Nakama.create_socket_from(client)

func _ready():
    var connected : NakamaAsyncResult = yield(socket.connect_async(session), "completed")

    if connected.is_exception():
        print("An error occurred: %s" % connected)
        return

    print("Socket connected.")
Client
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# Make this a node variable, or it will disconnect when the function that creates it returns.
@onready var socket := Nakama.create_socket_from(client)

func _ready():
    var connected : NakamaAsyncResult = await socket.connect_async(session)

    if connected.is_exception():
        print("An error occurred: %s" % connected)
        return

    print("Socket connected.")
Client
1
2
3
4
5
6
local socket = client.create_socket()
local ok, err = socket.connect()

if not ok then
  print("Unable to connect: ", err)
end
Client
1
2
3
4
5
6
7
8
let socket = client.createSocket()
socket.connect(session, appearOnline: true) { error in
    if let error = error {
        print("Error connecting socket: \(error)")
        return
    }
    print("Socket connected.")
}
Client
1
2
3
4
5
6
7
// Socket is automatically connected after initialization
final socket = NakamaWebsocketClient(
  host: '127.0.0.1',
  port: 7350,
  ssl: false,
  token: '<token>',
);

You can link one or more other login option to the current user. This makes it easy to support multiple logins with each user and easily identify a user across devices.

You can only link device Ids, custom Ids, and social provider IDs which are not already in-use with another user account.

Client
1
2
3
curl "http://127.0.0.1:7350/v2/account/link/custom" \
  --header 'Authorization: Bearer $session' \
  --data '{"id":"some-custom-id"}'
Client
1
2
3
4
5
6
7
8
POST /v2/account/link/custom
Host: 127.0.0.1:7350
Accept: application/json
Content-Type: application/json
Authorization: Bearer <session token>
{
  "id":"some-custom-id"
}
Client
1
2
3
const customId = "some-custom-id";
const success = await client.linkCustom(session, customId);
console.log("Successfully linked custom ID to current user.");
Client
1
2
3
const string customId = "some-custom-id";
await client.LinkCustomAsync(session, customId);
System.Console.WriteLine("Id '{0}' linked for user '{1}'", customId, session.UserId);
Client
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
auto linkFailedCallback = [](const NError& error)
{
};

auto linkSucceededCallback = []()
{
    cout << "Linked successfully" << endl;
};

std::string customid = "some-custom-id";

client->linkCustom(customid, linkSucceededCallback, linkFailedCallback);
Client
1
2
3
String customId = "some-custom-id";
client.linkCustom(session, customId).get();
System.out.format("Id %s linked for user %s", customId, session.getUserId());
Client
1
2
3
4
5
6
7
8
var custom_id = "some-custom-id"
var linked : NakamaAsyncResult = yield(client.link_custom_async(session, custom_id), "completed")

if linked.is_exception():
    print("An error occurred: %s" % linked)
    return

print("Id '%s' linked for user '%s'" % [custom_id, session.user_id])
Client
1
2
3
4
5
6
7
8
var custom_id = "some-custom-id"
var linked : NakamaAsyncResult = await client.link_custom_async(session, custom_id)

if linked.is_exception():
    print("An error occurred: %s" % linked)
    return

print("Id '%s' linked for user '%s'" % [custom_id, session.user_id])
Client
1
2
3
4
5
local result = client.link_custom(custom_id)

if result.error then
  print("An error occurred:", result.error)
end
Client
1
2
3
let customId = "<customId>"
let success = try await client.linkCustom(session: session, id: customId)
print("Successfully linked custom ID to current user.")
Client
1
2
3
4
5
final customId = '<customId>';
await client.linkCustom(
  session: session,
  id: customId,
);

You can unlink any linked login options for the current user.

Client
1
2
3
curl "http://127.0.0.1:7350/v2/account/unlink/custom" \
  --header 'Authorization: Bearer $session' \
  --data '{"id":"some-custom-id"}'
Client
1
2
3
4
5
6
7
8
POST /v2/account/unlink/custom
Host: 127.0.0.1:7350
Accept: application/json
Content-Type: application/json
Authorization: Bearer <session token>
{
  "id":"some-custom-id"
}
Client
1
2
3
const customId = "some-custom-id";
const success = await client.unlinkCustom(session, customId);
console.info("Successfully unlinked custom ID from the current user.");
Client
1
2
3
const string customId = "some-custom-id";
await client.UnlinkCustomAsync(session, customId);
System.Console.WriteLine("Id '{0}' unlinked for user '{1}'", customId, session.UserId);
Client
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
auto unlinkFailedCallback = [](const NError& error)
{
};

auto unlinkSucceededCallback = []()
{
    cout << "Successfully unlinked custom ID from the current user." << endl;
};

std::string customid = "some-custom-id";

client->unlinkCustom(customid, unlinkSucceededCallback, unlinkFailedCallback);
Client
1
2
3
String customId = "some-custom-id";
client.unlinkCustom(session, customId).get();
System.out.format("Id %s unlinked for user %s", customId, session.getUserId());
Client
1
2
3
4
5
6
7
8
var custom_id = "some-custom-id"
var unlinked : NakamaAsyncResult = yield(client.unlink_custom_async(session, custom_id), "completed")

if unlinked.is_exception():
    print("An error occurred: %s" % unlinked)
    return

print("Id '%s' unlinked for user '%s'" % [custom_id, session.user_id])
Client
1
2
3
4
5
6
7
8
var custom_id = "some-custom-id"
var unlinked : NakamaAsyncResult = await client.unlink_custom_async(session, custom_id)

if unlinked.is_exception():
    print("An error occurred: %s" % unlinked)
    return

print("Id '%s' unlinked for user '%s'" % [custom_id, session.user_id])
Client
1
2
3
4
5
local result = client.unlink_custom(custom_id)

if result.error then
  print("An error occurred:", result.error)
end
Client
1
2
3
let customId = "<customId>"
let success = try await client.unlinkCustom(session: session, id: customId)
print("Successfully unlinked custom ID from the current user.")
Client
1
2
3
4
5
final customId = '<customId>';
await client.unlinkCustom(
  session: session,
  id: customId,
);

You can link or unlink many different account options.

LinkDescription
AppleAn Apple account.
CustomA custom identifier from another identity service.
DeviceA unique identifier for a device which belongs to the user.
EmailAn email and password set by the user.
FacebookA Facebook social account. You can optionally import Facebook Friends upon linking.
Game CenterAn account from Apple’s Game Center service.
GoogleA Google account.
SteamAn account from the Steam network.