Setup & Guides
Platform setup, OAuth providers, email, error monitoring, and server hooks
JavaScript Client SDK View on NPM
1 Install the SDK
Install the package via npm:
2 Initialize the Client
Import and configure the API client:
const { ApiClient, HealthApi, AuthenticationApi, UsersApi } = require('@ughuuu/game_server');
// Initialize the API client
const apiClient = new ApiClient();
apiClient.basePath = 'http://localhost:4000';
3 Health Check
Test your connection with a health check:
const healthApi = new HealthApi(apiClient);
const healthResponse = await healthApi.index();
console.log('Server is healthy:', healthResponse);
4 Authentication
The API uses JWT tokens. Here's how to authenticate:
Email/Password Login:
const authApi = new AuthenticationApi(apiClient);
const loginResponse = await authApi.login({
loginRequest: {
email: 'user@example.com',
password: 'password123'
}
});
const { access_token, refresh_token } = loginResponse.data;
OAuth Flow (Discord, Google, Facebook):
// Step 1: Get authorization URL
const authResponse = await authApi.oauthRequest('discord');
const authUrl = authResponse.authorization_url;
const sessionId = authResponse.session_id;
// Step 2: Open URL in browser for user to authenticate
window.open(authUrl, '_blank');
// Step 3: Poll for completion
let sessionData;
do {
await new Promise(resolve => setTimeout(resolve, 1000));
sessionData = await authApi.oauthSessionStatus(sessionId);
} while (sessionData.status === 'pending');
if (sessionData.status === 'completed') {
const { access_token, refresh_token } = sessionData.data;
console.log('OAuth successful!');
}
Using Access Tokens:
// Set authorization header for authenticated requests
apiClient.defaultHeaders = {
'Authorization': `Bearer ${access_token}`
};
5 API Usage Examples
Get User Profile:
const usersApi = new UsersApi(apiClient);
const userProfile = await usersApi.getCurrentUser(`Bearer ${access_token}`);
console.log('User:', userProfile.data);
Refresh Token:
const refreshResponse = await authApi.refreshToken({
refreshTokenRequest: {
refresh_token: refresh_token
}
});
const newAccessToken = refreshResponse.data.access_token;
Logout:
await authApi.logout(`Bearer ${access_token}`);
console.log('Logged out successfully');
6 Error Handling
Handle common errors appropriately:
try {
const result = await someApiCall();
} catch (error) {
if (error.status === 401) {
// Token expired, refresh or re-authenticate
console.log('Token expired');
} else if (error.status === 403) {
// Forbidden - insufficient permissions
console.log('Access denied');
} else if (error.status === 404) {
// Resource not found
console.log('Not found');
} else {
// Other errors
console.error('API Error:', error);
}
}
7 Lobby Management
Work with lobbies for multiplayer matchmaking:
List Available Lobbies
const { LobbiesApi } = require('@ughuuu/game_server');
const lobbiesApi = new LobbiesApi(apiClient);
// List all public lobbies - note: the SDK returns the array directly
const lobbies = await lobbiesApi.listLobbies();
console.log('Available lobbies:', lobbies);
// Search lobbies by name/title
const searchResults = await lobbiesApi.listLobbies({ q: 'deathmatch' });
console.log('Search results:', searchResults);
Create a Lobby
// Create a new lobby (requires authentication via Authorization: Bearer <token>)
const newLobby = await lobbiesApi.createLobby({
title: 'My Game Room',
max_users: 4,
is_hidden: false,
metadata: { game_mode: 'deathmatch' }
});
// SDK returns the created lobby object directly
console.log('Created lobby:', newLobby);
Join / Leave
// Join a lobby by ID (authenticated)
await lobbiesApi.joinLobby(lobbyId);
// Join a password-protected lobby
await lobbiesApi.joinLobby(lobbyId, { password: 'secret123' });
// Leave the current lobby (authenticated)
await lobbiesApi.leaveLobby();
console.log('Left the lobby');
Update & Kick (host only)
// Update lobby settings (host only)
await lobbiesApi.updateLobby({
title: 'Updated Room Name',
max_users: 8,
is_locked: true
});
// Kick a user (host only)
await lobbiesApi.kickUser(123);
console.log('User kicked from lobby');
Friends
// Send a friend request
const { FriendsApi } = require('@ughuuu/game_server');
const friendsApi = new FriendsApi(apiClient);
await friendsApi.create({ target_user_id: someOtherUserId });
// List my friends
const friends = await friendsApi.listFriends();
console.log('Friends:', friends);
// Subscribe to real-time friend events via phoenix channels on socket
const socket = new Socket('/socket', { params: { token: accessToken } });
socket.connect();
const userChannel = socket.channel('friends:user:' + userId, {});
await userChannel.join();
userChannel.on('friend_blocked', payload => console.log('Blocked:', payload));
userChannel.on('friend_unblocked', payload => console.log('Unblocked:', payload));
Realtime / subscribing to events
// The server exposes real-time events via Phoenix channels on the same socket
// (you must pass a valid JWT token when connecting).
// Using the phoenix JS client (https://www.npmjs.com/package/phoenix)
import { Socket } from 'phoenix';
const socket = new Socket('/socket', { params: { token: accessToken } });
socket.connect();
// === per-user updates ===
// join the "user_updates:<userId>" topic to receive events about that user
const userChannel = socket.channel('user_updates:' + userId, {});
await userChannel.join();
userChannel.on('metadata_updated', (payload) => {
console.log('My metadata changed', payload);
});
// === per-lobby updates ===
// join "lobby:<lobby_id>" to receive membership and lobby events
const lobbyChannel = socket.channel('lobby:' + lobbyId, {});
await lobbyChannel.join();
// events forwarded from the server: user_joined, user_left, user_kicked, lobby_updated, host_changed
lobbyChannel.on('user_joined', ({ user_id }) => console.log('User joined', user_id));
lobbyChannel.on('user_left', ({ user_id }) => console.log('User left', user_id));
lobbyChannel.on('user_kicked', ({ user_id }) => console.warn('You were kicked', user_id));
lobbyChannel.on('lobby_updated', (lobby) => console.log('Lobby updated', lobby));
lobbyChannel.on('host_changed', ({ new_host_id }) => console.log('Host changed', new_host_id));
Godot Client SDK View on Godot Asset Library
1 Get the Asset
Download the Godot asset from the Asset Library (in Godot look for the "Gamend - Game Server" addon):
2 Quick integration
Typical usage inside Godot GDScript (pseudocode / example):
var gamend_api:= GamendApi.new()
var access_token := ""
var refresh_token := ""
# This function will be reused in future examples
func print_error_or_result(response: GamendResult):
if response.error:
print(response.error)
else:
print(response.response)
func _ready() -> void:
var response :GamendResult= await gamend_api.health_index().finished
print_error_or_result(response)
3 Authentication
Authenticate using the same JWT-based API flow as other SDKs (get token from server login / OAuth).
var gamend_api:= GamendApi.new()
var access_token := ""
var refresh_token := ""
func _ready() -> void:
# Request OAuth URL, open browser and login
do_discord_auth()
gamend_api.authorize(access_token)
func do_discord_auth():
var response = await gamend_api.authenticate_oauth_request(GamendApi.PROVIDER_DISCORD).finished
print_error_or_result(response)
var authorization_url = response.response.data.authorization_url
var session_id :String = response.response.data.session_id
# Opening Auth URL
OS.shell_open(authorization_url)
for i in 60:
print("CHECKING SESSION: ", session_id)
response = await gamend_api.authenticate_oauth_session_status(session_id).finished
print_error_or_result(response)
if response.response.data.status == "completed":
break
access_token = response.response.data.data.access_token
refresh_token = response.response.data.data.refresh_token
4 Call Authenticated APIs
After logging in, you can now call any RPC or other protected functions.
var gamend_api:= GamendApi.new()
func _ready() -> void:
# From previous example
gamend_api.authorize(access_token)
# ...
response = await gamend_api.users_get_current_user().finished
print_error_or_result(response)
var call_hook := CallHookRequest.new()
call_hook.fn = "hello"
call_hook.args = ["1"]
response = await gamend_api.hooks_call_hook(call_hook).finished
print_error_or_result(response)
Server-side scripting & hooks Scrpting Interface
The application exposes a lightweight server-side scripting surface via the
GameServer.Hooks
behaviour. Hooks let you run
custom code on lifecycle events (eg. user register/login, lobby create/update)
and optionally expose RPC functions.
Add a lifecycle callback
Implement the behaviour in the modules folder:
# modules/my_hooks_impl.ex
defmodule MyApp.HooksImpl do
@behaviour GameServer.Hooks
@impl true
def after_user_register(user) do
# safe database update (non-blocking in hooks is recommended)
GameServer.Accounts.update_user(user, %{metadata: Map.put(user.metadata || %{}, "from_hook", true)})
:ok
end
end
Registering a runtime hook file
You can register a hooks implementation file at runtime by setting the following configuration:
HOOKS_FILE_PATH=modules/my_hooks_impl.ex
This file will be compiled and loaded on application start. On changes, it will auto-reload without restarting the server.
Exposing an RPC function
Hooks modules can also export arbitrary functions:
defmodule MyApp.HooksImpl do
@behaviour GameServer.Hooks
def hello_world(name) do
{:ok, "Hello, #{name}!"}
end
end
curl -X POST https://your-game-server.com/api/v1/hooks/call \
-d '{"fn":"hello_world","args":["Alice"]}'
Best practices & pitfalls
-
Keep hooks fast and resilient — avoid long blocking work in the main request path. Use
Task.startfor background processing. -
When returning values from lifecycle hooks, prefer a
{:ok, map}shape for "before" hooks that may modify attrs. Return{:error, reason}to reject flows; domain code will convert to{:hook_rejected, reason}. - Do not return structs as hook results intended to be used as params — always return plain maps when you intend to pass modified params into changesets.
-
Tests interacting with runtime registration or global
:hooks_moduleconfig should run serially (setasync: falsein the test) and restore Application env viaon_exitto avoid cross-test races. -
Be careful modifying user or lobby data from hooks — reuse high-level domain functions (eg.
GameServer.Accounts.update_user/2,GameServer.Lobbies.update_lobby/2) so changes are validated and broadcast consistently.
Configure Theme
You can provide simple runtime theming configuration using a JSON file. This lets you customize basic branding (title, tagline) and reference an external stylesheet (css) plus assets (logo, banner).
2 Configure theming JSON
Place a JSON file somewhere in your project, for example:
theme/default_config.json
With the following:
{
"title": "My Game",
"tagline": "Play together",
"css": "/theme/theme.css",
"logo": "/theme/logo.png",
"banner": "/theme/banner.png"
}
2 Configure the app to use it
Point the runtime configuration at the JSON file:
THEME_CONFIG=theme/default_config.json
Data Schema API Docs
This section describes the main database table shapes used by the platform - starting with the
users
table and the important fields you may rely on.
Users table
users (
id : integer (primary key)
email : string (unique, nullable for provider-only accounts)
hashed_password: string (bcrypt hash, nullable for OAuth-only accounts)
confirmed_at : utc_datetime
authenticated_at: utc_datetime (last sudo login)
discord_id : string (nullable)
google_id : string (nullable)
facebook_id : string (nullable)
steam_id. : string (nullable)
apple_id : string (nullable)
profile_url : string (avatar/profile image URL)
display_name : string (human-friendly display name)
is_admin : boolean
metadata : map (JSON/Map for arbitrary user metadata)
inserted_at : utc_datetime
updated_at : utc_datetime
)
Friends
friendships (
id : integer (primary key)
requester_id: integer (user id of who made the request)
target_id : integer (user id of the target)
status : string ("pending" | "accepted" | "rejected" | "blocked")
inserted_at : utc_datetime
updated_at : utc_datetime
)
Lobbies
lobbies (
id : integer (primary key)
name : string (unique slug)
title : string (display title)
host_id : integer (user id of host, nullable for hostless)
hostless : boolean (server-managed hostless lobbies)
max_users : integer (maximum number of members)
is_hidden : boolean (not returned by public lists)
is_locked : boolean (fully locked - prevents joins)
password_hash: string (bcrypt hash, optional: requires password to join)
metadata : jsonb/map (searchable metadata)
inserted_at : utc_datetime
updated_at : utc_datetime
)
Notes / behavior
-
Password auth:
Accounts created only via OAuth commonly have no
hashed_password. In that case password-based login does not work (we treat oauth-only accounts as passwordless unless a password is explicitly set by the user). -
Display name:
The
display_nameis a human-friendly name and may be populated from OAuth providers (when available). The app avoids overwriting a user-provided display name when linking providers. -
Profile image:
The
profile_urlis used for avatars and may be populated from provider responses (Google picture, Facebook picture.data.url, Discord CDN). -
Metadata:
The JSON
metadatafield is for arbitrary application data (e.g. display preferences). It's returned by the public API atGET /api/v1/me.
Persisted data and tables
The platform stores several tables worth of data that client integrations may need to be aware of.
Users
The users
table is the primary identity store and contains
fields like email, hashed_password,
provider ids (discord_id, google_id, etc.), profile_url, display_name,
metadata
and admin flags and timestamps.
User tokens (users_tokens)
users_tokens (
id : integer (primary key)
token : binary (hashed for email tokens; raw for session tokens)
context : string ("session", "login", "change:..." etc.)
sent_to : string (email address for email/magic link tokens)
authenticated_at: utc_datetime (when this session was created/used)
user_id : integer (foreign key to users)
inserted_at : utc_datetime
)
The app persists session tokens to let users view/expiration/and revoke individual sessions. Email/magic-link tokens are hashed when stored for safety.
OAuth sessions (oauth_sessions)
oauth_sessions (
id : integer (primary key)
session_id: string (unique id used by SDKs to poll/signal status)
provider : string ("discord" | "google" | "facebook" | "apple" | "steam")
status : string ("pending" | "completed" | "failed")
data : jsonb/map (provider response, debug info, or result payload)
inserted_at: utc_datetime
updated_at: utc_datetime
)
OAuth sessions are tracked in the DB to support reliable polling flows from client SDKs and to provide safe, multi-step authorization from popups and mobile apps.
JWT tokens (access + refresh)
The API issues JSON Web Tokens (JWTs) for API authentication. Access tokens are short-lived and refresh tokens are longer-lived (configurable). The server uses Guardian for signing and verification. Refresh tokens are stateless JWTs (no DB lookup) while session tokens and email tokens are persisted where needed.
Apple Sign In Setup Apple Developer Portal
1 Apple Developer Account
You need an Apple Developer Account ($99/year)
2 Create App ID
Go to Certificates, Identifiers & Profiles
- Click the "+" button to create a new identifier
- Select "App IDs" and click Continue
- Select "App" type and click Continue
- Enter a description (e.g., "Game Server")
- Enter a Bundle ID (e.g., com.yourcompany.gameserver)
- Scroll down and check "Sign in with Apple"
- Click Continue and Register
3 Create Service ID (Client ID)
Back in Certificates, Identifiers & Profiles:
- Click "+" to create new identifier
- Select "Services IDs" and click Continue
- Enter description (e.g., "Game Server Web")
- Enter identifier (e.g., com.yourcompany.gameserver.web) - This is your CLIENT_ID
- Check "Sign in with Apple"
- Click "Configure" next to Sign in with Apple
- Select your App ID as the Primary App ID
-
Add these domains and redirect URLs:
Domain: example.comReturn URL: https://example.com/auth/apple/callback - Click Save, then Continue, then Register
4 Create Private Key
In Certificates, Identifiers & Profiles, go to Keys:
- Click "+" to create a new key
- Enter a name (e.g., "Game Server Sign in with Apple Key")
- Check "Sign in with Apple"
- Click "Configure" next to Sign in with Apple
- Select your App ID as the Primary App ID
- Click Save, then Continue
- Click Register
- Download the .p8 file - you can only download this once!
- Note the Key ID (e.g., ABC123XYZ) shown on the confirmation page
5 Get Your Team ID
Find your Team ID:
- Go to Membership Details
- Your Team ID is listed there (10 characters, e.g., A1B2C3D4E5)
6 Configure Environment Variables
Set these environment variables:
7 Test Apple Sign In
After deploying with the secrets:
- Go to your app's login page
- Click "Sign in with Apple"
- Authorize the application with your Apple ID
- You should be redirected back and logged in
Steam OpenID Setup Steam Dev Portal
1 Get a Steam Web API Key
Visit the Steam Web API page at https://steamcommunity.com/dev and register your domain to get an API key.
2 Configure Redirect Domain
Steam uses OpenID for sign-in. When registering your domain at
steamcommunity.com/dev
, enter your domain (e.g.,
example.com
for production or localhost:4000
for development).
3 Configure Environment Variables
Set the following environment variable:
4 Test Steam Login
After configuring the API key:
- Go to your app's login page
- Click "Sign in with Steam"
- Authorize with your Steam account
- You should be redirected back and logged in
Note:
For linking Steam to an existing account, go to /users/settings
and click "Link Steam".
Discord OAuth Setup Discord Developer Portal
1 Create Discord Application
Go to the Discord Developer Portal
- Click "New Application" in the top right
- Give your app a name (e.g., "Game Server")
- Go to the "OAuth2" → "General" tab
2 Configure Redirect URIs
In the OAuth2 General settings, add these redirect URIs:
These are the URLs Discord will redirect users back to after authorization.
3 Get Application Credentials
From the OAuth2 General tab, copy these values:
4 Configure Application Secrets
Set these environment variables:
5 Test Discord Login
After deploying with the secrets:
- Go to your app's login page
- Click "Sign in with Discord"
- Authorize the application on Discord
- You should be redirected back and logged in
Google OAuth Setup Google Cloud Console
1 Create Google Cloud Project
Go to the Google Cloud Console
- Click "Select a project" at the top
- Click "New Project"
- Enter a project name (e.g., "Game Server")
- Click "Create"
2 Enable Google+ API
In your Google Cloud project:
- Go to "APIs & Services" → "Library"
- Search for "Google+ API"
- Click on it and click "Enable"
3 Configure OAuth Consent Screen
Go to "APIs & Services" → "OAuth consent screen":
- Select "External" user type
- Click "Create"
- Fill in app name (e.g., "Game Server")
- Add your email as user support email
- Add authorized domains (e.g., example.com)
- Add developer contact email
- Click "Save and Continue"
- Add scopes: email, profile
- Click "Save and Continue"
- Add test users if needed (optional for development)
4 Create OAuth Credentials
Go to "APIs & Services" → "Credentials":
- Click "Create Credentials" → "OAuth client ID"
- Select "Web application"
- Enter a name (e.g., "Game Server Web")
-
Add authorized redirect URIs:
Development: http://localhost:4000/auth/google/callbackProduction: https://example.com/auth/google/callback - Click "Create"
- Copy the Client ID and Client Secret
5 Configure Environment Variables
Set these environment variables:
6 Test Google Login
After deploying with the secrets:
- Go to your app's login page
- Click "Sign in with Google"
- Choose your Google account
- You should be redirected back and logged in
Facebook OAuth Setup Facebook Developers Portal
1 Create Facebook App
Go to the Facebook Developers Portal
- Click "My Apps" in the top right
- Click "Create App"
- Select the use case that fits your needs (often "Other" or "Authenticate and request data from users with Facebook Login")
- Click "Next"
- Select app type (usually "Business" for most web apps, or "None" if available)
- Click "Next"
- Enter app name (e.g., "Game Server")
- Enter contact email
- Click "Create App"
2 Add Facebook Login Product
In your Facebook App dashboard:
- Find "Facebook Login" in the product list
- Click "Set Up"
- Select "Web" as the platform
- Enter your site URL (e.g., https://example.com)
- Click "Save" and continue
3 Configure OAuth Redirect URIs
Go to "Facebook Login" → "Settings":
-
Add these Valid OAuth Redirect URIs:
Development: http://localhost:4000/auth/facebook/callbackProduction: https://example.com/auth/facebook/callback - Click "Save Changes"
4 Get App Credentials
Go to "Settings" → "Basic":
- Copy the "App ID" (this is your Client ID)
- Click "Show" next to "App Secret" and copy it (this is your Client Secret)
5 Make App Public (Production)
For production use, switch to live mode:
- Complete all required fields in "Settings" → "Basic"
- Add a Privacy Policy URL
- Add a Terms of Service URL (optional)
- Select a category for your app
- Toggle the switch at the top from "Development" to "Live"
6 Configure Environment Variables
Set these environment variables:
7 Test Facebook Login
After deploying with the secrets:
- Go to your app's login page
- Click "Sign in with Facebook"
- Authorize the application with your Facebook account
- You should be redirected back and logged in
Email Setup Email Implementation Docs
Choose an Email Provider
Recommended providers:
Configure Email Secrets
Set these environment variables based on your provider:
Important — From address & domain verification
Many email providers require that the "From" address or sending domain
be verified in your SMTP provider dashboard before they'll accept or relay mail
(you may see errors like "450 domain not verified"). Configure
SMTP_FROM_NAME
and SMTP_FROM_EMAIL
so that
your messages use a verified sender and avoid delivery rejections.
If you're not sure what to use, set SMTP_FROM_EMAIL to an
address in a domain you control (eg. no-reply@yourdomain.com) and
verify that domain with your provider.
Tip: you can review and test the current runtime SMTP settings in the admin Admin • Configuration page.
For other providers, adjust the SMTP settings accordingly. The app will automatically detect when email is configured.
Sentry Setup Sentry Dashboard
1 Create Sentry Project
Go to the Sentry Dashboard
- Sign up or log in to Sentry
- Create a new project
- Select "Phoenix" or "Elixir" as the platform
- Name your project (e.g., "Game Server")
2 Get Your DSN
After creating the project, copy the DSN from the settings:
- Go to Project Settings → Client Keys (DSN)
- Copy the DSN value
3 Set Environment Variable
Set the SENTRY_DSN environment variable:
4 Deploy and Test
After deploying with the DSN:
- Deploy your application
- Check the admin config page - Sentry should show as "Configured"
- Test error reporting by running:
mix sentry.send_test_event - Check your Sentry dashboard for the test event
PostgreSQL Setup Download PostgreSQL
Database URL Configuration
Set the DATABASE_URL environment variable:
The app will automatically detect PostgreSQL when DATABASE_URL is set and contains "postgresql://".
Individual Environment Variables (Alternative)
You can also set individual database connection variables:
Deployment Considerations
Popular PostgreSQL hosting options: