A small self-hosted admin API for WorkAdventure, for instances that log in through OpenID Connect (tested with Authentik).
WorkAdventure without an admin API keeps the chosen woka only in the browser and reads roles only at login. With this server:
-
Roles are live. On every page load and room change the user's roles are read from the OpenID provider's userinfo endpoint with the user's access token (claim
tagsby default). Group changes apply after a reload, no new login needed. The last known roles are used as a fallback. -
Wokas and companions are saved per account, so they follow the user to every browser and device. A woka chosen in the browser before the admin API existed is taken over on the first visit.
-
Own avatars and cosmetics, uploaded in the admin UI (complete characters, builder parts, hats, accessories, companions) and unlocked for everyone, roles, a season or single people.
-
Admin UI (login through OpenID Connect, admin role only): avatars & cosmetics, members with their roles, when they were last online (and who is online now, with the Matrix settings), player reports.
-
Map editor rights come from roles (
EDITOR_TAGS, defaultadmin,editor) or a list of users. -
Room list from the map storage, with relative thumbnails (e.g. the
mapImageof the Tiled map) turned into working URLs. -
Room access by role or person, names and descriptions for the room list, hidden rooms (admin UI → Räume).
-
Personal rooms: every player can create their own room from a template map (profile tab in WorkAdventure), decorate it with the map editor and decide who may enter. Each personal room gets its own preview picture, drawn from its map and the furniture placed in it, and drawn again when the room changes (shown in the profile, the admin room list and link previews; kept in
DATA_DIR/room-previews, the.wamis not touched). -
Bans from the admin UI or WorkAdventure's own ban button.
-
Visit cards with role badges, and a profile tab (
OPENID_PROFILE_SCREEN_PROVIDER=<PUBLIC_URL>/profile). -
More choice in the woka builder: 8 extra hair colours for every hairstyle, 6 eye colours and glasses, recoloured from WorkAdventure's own sprites. On top come hand-drawn office and gaming accessories (coffee mug, coffee to go, laptop, clipboard, smartphone, ID badges, controller, handheld console, energy drink) and headsets (gaming, cat ears, office, VR) that sit in the hat slot, so they can be combined with an accessory. Generated by
tools/gen-parts.py(which usestools/gen_accessories.py), served under/files/parts/; needsPUBLIC_URL. -
Avatars & cosmetics (admin UI → Avatare & Cosmetics): 24 hand-drawn items in sets (
data/cosmetics/cosmetics.json, drawn bytools/gen_cosmetics.pyat the size of WorkAdventure's own sprites), offered in the woka builder and the companion list only to players who have them:- Seasonal (Halloween 1 Oct–7 Nov, winter 1 Dec–6 Jan, summer June–August, with the sunglasses): anyone can pick them during the season, and whoever is online then keeps them for good.
- Roles: crown and royal robe for admins.
- For everyone: gamer hoodie, arcade shirt, trophy, medal, party hat, and a dragon and a frog as companions.
- Admins can also hand out any item, to one member or to everyone who was online on a given day (e.g. an event evening), and take it back.
The admin page lists who has each item and why (everyone, role, season, given by an admin). Given and earned items are stored in the database. Admins get nothing automatically: only what their roles unlock or what they are given. Players see what they have and how to get the rest in the profile tab. Needs
PUBLIC_URL; images are served under/files/cosmetics/. Admins also upload their own items there: complete characters, builder parts (body, eyes, hair, clothes, hat, accessory) and companions, each with German and English names, a group and an unlock rule. New items start as "only for certain people", handed out on the item's page. Pictures are kept inDATA_DIR/cosmetics. Avatars uploaded with older versions (tablecustom_wokas,DATA_DIR/wokas) are moved there on start: "everyone" and roles stay, people they were shared with get them handed out. -
More official wokas: the ~270 Pipoya characters that WorkAdventure ships but does not offer by default, as extra collections (men, women, school, animals).
-
Invites: registration links created through the authentik API, from the admin UI or (admins only) in the game.
-
Member and tag search, player reports, and chat upload limits for the uploader.
-
German and English for everything players see (visit cards, profile tab, ban and access messages): they follow the browser language, which WorkAdventure forwards. The admin UI has both languages too, with a switch in the sidebar.
No runtime dependencies: Node.js 22 with the built-in node:sqlite.
| Endpoint | Used by WorkAdventure for |
|---|---|
GET /api/capabilities |
feature detection (api/woka/list, api/companion/list, api/save-textures) |
GET /api/map |
room → map URL, redirects, room settings |
GET /api/room/access |
roles, woka, companion, map editor right per user |
GET /api/woka/list, GET /api/companion/list |
character and companion selection |
POST /api/save-textures, POST /api/save-companion-texture |
saving the selection |
GET /api/room/sameWorld |
room list |
GET /api/room/tags, GET /api/world/tags |
role suggestions in the map editor |
GET /api/members, GET /api/members/:id, GET /api/chat/members |
member search |
POST /api/report |
player reports (stored in the database) |
GET /api/limit/fileSize |
chat upload size check by the uploader |
All endpoints except capabilities, logout and the upload check require Authorization: <ADMIN_API_TOKEN>.
| Variable | Default | Description |
|---|---|---|
ADMIN_API_TOKEN |
– (required) | Shared secret, same value as in WorkAdventure |
PUBLIC_MAP_STORAGE_URL |
– (required) | e.g. https://play.example.com/map-storage |
INTERNAL_MAP_STORAGE_URL |
http://map-storage:3000 |
Map storage inside the Docker network |
OIDC_ISSUER |
– | Issuer URL of the OpenID application, enables live roles |
OIDC_TAGS_CLAIM |
tags |
Claim containing the roles |
OIDC_USERNAME_CLAIM |
preferred_username |
Shown in member search |
START_ROOM_URL |
/~/maps/office.wam |
Where / redirects to |
DISABLE_ANONYMOUS |
true |
Require login |
OPENID_WOKA_NAME_POLICY |
allow_override_opid |
user_input, allow_override_opid or force_opid |
ENABLE_MAP_EDITOR |
true |
|
EDITOR_TAGS |
admin,editor |
Roles that may use the map editor |
MAP_EDITOR_ALLOWED_USERS |
– | Additional users (emails) for the map editor |
KNOWN_TAGS |
admin,editor,moderator,freunde,vip,member |
Roles offered in the map editor |
ENABLE_CHAT, ENABLE_CHAT_UPLOAD, ENABLE_CHAT_ONLINE_LIST, ENABLE_CHAT_DISCONNECTED_LIST, ENABLE_SAY |
true |
|
ENABLE_ISSUE_REPORT |
false |
|
ENABLE_TUTORIAL |
true |
|
UPLOAD_MAX_FILESIZE |
10485760 |
Chat upload limit in bytes |
PERSONAL_ROOM_TEMPLATE |
– | Map copied for personal rooms, e.g. maps/zimmer.wam; enables personal rooms. Further styles are found automatically: every zimmer-stil-<key>.wam in the same folder (known keys: loft, gemuetlich, dunkel, gross; the template itself is holz). Players pick a style in their profile and can switch later, which replaces the room's map |
MATRIX_DOMAIN |
– | Same value as WorkAdventure's MATRIX_DOMAIN. Enables the Matrix chat (direct messages, chat rooms) and gives members their Matrix id @<username>:<MATRIX_DOMAIN>. Synapse must create accounts the same way: `localpart_template: "{{ user.preferred_username |
MATRIX_API_URL |
– | Synapse as seen from this container, e.g. http://synapse:8008. Together with the next two, "last seen" on the members page becomes the last activity in the chat (when someone really had WorkAdventure open, read every 2 minutes) and members active in the last 5 minutes are shown as online. Without them it is the last time someone entered a room |
MATRIX_ADMIN_USER |
– | WorkAdventure's Matrix admin user (localpart, same as its MATRIX_ADMIN_USER); needs to be a Synapse admin |
MATRIX_ADMIN_PASSWORD |
– | Its password |
PERSONAL_ROOM_DIR |
zimmer |
Map storage folder for personal rooms. Must not be a folder you upload maps to: an upload deletes every map in its folder that is not part of the upload |
MAP_STORAGE_TOKEN |
– | Map storage API token (MAP_STORAGE_AUTHENTICATION_TOKEN), needed to copy the template |
PERSONAL_ROOM_TAGS |
– | Roles that may create a personal room (empty: everyone logged in) |
DATA_DIR |
/data |
SQLite database and uploaded wokas (writable by UID 1000) |
The UI runs on a second port (UI_PORT, default 3001) and is only enabled when PUBLIC_URL, OIDC_ISSUER, OIDC_CLIENT_ID and OIDC_CLIENT_SECRET are set. Only that port should be published behind the reverse proxy; the API port stays inside the Docker network. Uploaded images are served publicly from /files/cosmetics/ (with CORS), because players' browsers load them.
| Variable | Default | Description |
|---|---|---|
PUBLIC_URL |
– | e.g. https://workadventure-admin.example.com |
OIDC_CLIENT_ID, OIDC_CLIENT_SECRET |
– | OpenID client; the WorkAdventure client can be reused if PUBLIC_URL/callback is added as redirect URI |
OIDC_SCOPE |
openid email profile wa |
Must include the scope that provides the roles claim |
ADMIN_TAG |
admin |
Role required to log in |
APPLICATIONS_FILE |
data/applications.json |
Apps players can share in the chat and place with the map editor (skribbl.io and Gartic Phone by default) |
PLAY_URL |
– | WorkAdventure URL, to show official wokas in the member list |
OIDC_LOGOUT_URL |
end-session URL from discovery | Where WorkAdventure's "log out" leads after revoking the token, so the Authentik session ends as well. off keeps WorkAdventure's default (players are logged straight back in) |
UI_PORT |
3001 |
|
TIME_ZONE |
TZ, else Europe/Berlin |
Time zone for dates in the admin UI and for the cosmetics seasons |
SITE_NAME |
WorkAdventure |
Name in link previews (Discord etc.) and the browser tab, combined with the room name |
SITE_DESCRIPTION |
– | Preview text when a room has no description of its own (set those in the admin UI under Rooms) |
SITE_IMAGE |
PUBLIC_URL/files/og-image.png |
Preview image, 1200 × 630 |
AUTHENTIK_TOKEN |
– | authentik API token. Enables invites: an "Invites" page in the admin UI, and admins can create a link in the game under Menu → Profile |
AUTHENTIK_URL |
origin of OIDC_ISSUER |
authentik base URL |
INVITE_FLOW |
wa-einladung |
Slug of the enrollment flow that contains the invitation stage |
INVITE_DAYS |
7 |
Default validity of new invites |
Uploaded images must be PNGs of 96 × 128 pixels: 3 walking frames side by side, 4 directions below each other (down, left, right, up). A complete character uses the type woka; parts (body, eyes, hair, clothes, hat, accessory) are layered over each other like the official ones.
Add the service to the WorkAdventure compose stack so that play, back and uploader can reach it, and set in WorkAdventure's environment:
ADMIN_API_URL=http://workadventure-admin:3000
ADMIN_API_TOKEN=<random secret>
workadventure-admin:
image: ghcr.io/newtox/wa-admin-server:latest
restart: unless-stopped
environment:
ADMIN_API_TOKEN: ${ADMIN_API_TOKEN}
OIDC_ISSUER: ${OPENID_CLIENT_ISSUER}
OIDC_CLIENT_ID: ${OPENID_CLIENT_ID}
OIDC_CLIENT_SECRET: ${OPENID_CLIENT_SECRET}
PUBLIC_URL: https://workadventure-admin.example.com
PLAY_URL: https://${DOMAIN}
PUBLIC_MAP_STORAGE_URL: https://${DOMAIN}/map-storage
START_ROOM_URL: ${START_ROOM_URL}
DISABLE_ANONYMOUS: ${DISABLE_ANONYMOUS}
OPENID_WOKA_NAME_POLICY: ${OPENID_WOKA_NAME_POLICY}
ports:
- "127.0.0.1:8096:3001" # admin UI only
volumes:
- /docker_volumes/workadventure/admin:/dataRemoving ADMIN_API_URL switches WorkAdventure back to its built-in behaviour.
npm ci
ADMIN_API_TOKEN=dev PUBLIC_MAP_STORAGE_URL=http://localhost/map-storage npm run devdata/woka.json and data/companions.json are the default woka and companion lists of WorkAdventure (AGPL-3.0, artwork CC-BY-SA), so official wokas keep working unchanged.
This project is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike (CC BY-NC-SA) License.
- License: CC BY-NC-SA 4.0