Apollo PS4 Multi-User Support Implementation: Configuring user_id and account_id
Apollo PS4 implements multi-user support by storing the active user's user_id and account_id in a global app_config_t structure, using these identifiers to isolate save data, trophy databases, and online storage paths per PS4 user profile.
The multi-user support implementation in Apollo PS4 ensures that each PlayStation 4 user profile maintains isolated access to saves, trophies, and configuration data. This open-source tool by bucanero/apollo-ps4 retrieves the active user's identifiers directly from the PS4 OS and propagates them throughout the codebase to construct user-specific file paths and database connections.
Where the Identifiers Live
The user_id and account_id are defined in include/settings.h as members of the app_config_t structure:
user_id(uint32_t): The PSN user ID used for local sandboxing (declared at lines 40-42)account_id(uint64_t): The NP (Network Platform) account ID for online services (declared at lines 42-44)
Both fields are part of the global apollo_config instance declared in main.c, making the identifiers accessible throughout the application.
How the Identifiers Are Obtained
Retrieving user_id
At startup, Apollo reads the active user ID from the pad controller configuration:
// main.c – after SDL & pad init (line 246)
apollo_config.user_id = orbisPadGetConf()->userId;
The orbisPadGetConf() function returns a structure containing the OS-assigned user ID for the currently active user profile.
Resolving account_id
The account_id is resolved from the user_id during configuration loading in source/settings.c:
// settings.c – load_app_settings() (lines 73-76)
sceUserServiceGetNpAccountId(config->user_id, &config->account_id);
The sceUserServiceGetNpAccountId system call maps the local 32-bit user ID to the globally unique 64-bit NP account ID. This value persists to the settings file whenever the configuration is saved.
Persistence of the IDs
When settings are saved via save_app_settings() in source/settings.c, both identifiers are written to the user's save data partition:
// settings.c – inside save_app_settings() (line 404)
file_data->user_id = config->user_id;
file_data->account_id = config->account_id;
Each PS4 user maintains a separate settings.bin file, ensuring complete isolation of configuration data between profiles.
How the IDs Are Used Throughout the Codebase
File-System Paths
The user_id is embedded in paths for save data and trophy databases. In main.c, the update_hdd_path() and update_trophy_path() functions format paths using apollo_config.user_id:
// main.c – update_trophy_path() (lines 44-51)
snprintf(path, sizeof(path), TROPHY_DB_PATH, apollo_config.user_id);
This generates user-specific paths like /system_data/savedata/%08x/db/user/savedata.db.
Online Storage Paths
When online mode is enabled, the account_id is appended to FTP URLs to create isolated cloud folders:
// main.c – update_db_path() (lines 55-61)
sprintf(path, "%s%016lX/", apollo_config.ftp_url, apollo_config.account_id);
SQLite Database Operations
In source/sqlite_db.c, the appdb_rebuild() function creates per-user table names:
// sqlite_db.c – appdb_rebuild() (lines 207-236)
snprintf(path, sizeof(path),
"SELECT 1 FROM tbl_appbrowse_%010d WHERE titleId='%s'",
userid, dirp->d_name);
SFO File Patching
When patching save files, source/sfo.c injects both identifiers into the param.sfo file:
// sfo.c – patch_sfo() calls these:
sfo_patch_user_id(sfo, patches->user_id); // writes USER_ID into PARAMS
sfo_patch_account(sfo, patches->account_id); // writes ACCOUNT_ID field
This ensures the PS4 OS recognizes the save as belonging to the active user profile.
UI Display
The About screen in source/menu_about.c displays both identifiers:
// menu_about.c (lines 71-72)
snprintf(user_id_str, sizeof(user_id_str), "%08x", apollo_config.user_id);
snprintf(account_id_str, sizeof(account_id_str), "%016lx", apollo_config.account_id);
Key Files
| File | Purpose |
|---|---|
include/settings.h |
Defines app_config_t structure containing user_id and account_id |
main.c |
Global apollo_config instance, initPad(), path-building helpers |
source/settings.c |
Load/save configuration, sceUserServiceGetNpAccountId resolution |
source/sfo.c |
sfo_patch_user_id() and sfo_patch_account() functions |
source/sqlite_db.c |
Per-user database handling in appdb_rebuild() |
source/exec_cmd.c |
Remote FTP/HTTP command construction using account_id |
source/menu_about.c |
UI display of both identifiers |
Summary
- Apollo PS4 stores the active user's
user_id(32-bit) andaccount_id(64-bit) in the globalapp_config_tstructure namedapollo_config. - The
user_idis obtained fromorbisPadGetConf()->userIdat startup, whileaccount_idis resolved viasceUserServiceGetNpAccountId()during settings loading. - Both identifiers persist to a per-user
settings.binfile, ensuring isolation between PS4 user profiles. - Throughout the codebase, these IDs construct file-system paths, SQLite table names, FTP URLs, and SFO file patches, enabling complete multi-user support for saves, trophies, and online storage.
Frequently Asked Questions
How does Apollo determine which PS4 user is currently active?
Apollo reads the active user ID directly from the PS4 OS pad configuration. During initialization in main.c, the code assigns apollo_config.user_id = orbisPadGetConf()->userId, which returns the 32-bit user identifier assigned by the system to the currently logged-in profile.
What is the difference between user_id and account_id in Apollo?
The user_id is a 32-bit local identifier used by the PS4 OS for sandboxing and local user management, while the account_id is a 64-bit NP (Network Platform) identifier used for online services and global account recognition. Apollo uses user_id for local file paths and database names, and account_id for remote FTP/HTTP storage paths.
Where are the user identifiers stored in Apollo's configuration?
Both identifiers are stored in the global apollo_config instance of type app_config_t, defined in include/settings.h and instantiated in main.c. They persist to a binary settings file (settings.bin) located in the user's save data partition, with each PS4 user maintaining a separate copy of this file.
How does Apollo prevent save data from leaking between different user profiles?
Apollo enforces isolation by embedding the user_id into every file-system path, database query, and SFO patch operation. Functions like update_hdd_path() and update_trophy_path() in main.c format paths using the current user's ID, while sfo_patch_user_id() ensures that modified save files are stamped with the correct user identifier, preventing the PS4 OS from cross-associating saves between profiles.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →