Account Sync
The Account Sync page manages multi-site account synchronization: users, roles, and passwords created on the tenant's primary site (the account source) are pushed automatically to every other GEM server in the tenant, so one set of credentials works everywhere.
Open Account Sync
Roles
Every server is in exactly one of three states, and the page adapts:
- Account source (the primary / auth server) — full control: choose what gets synced, watch per-peer push status, and push a manual full sync.
- Managed peer — read-only status view showing how the server was provisioned, the current key generation, and when the last sync was applied (remembered across restarts). Accounts on this server are pushed from the primary; local account editing is disabled (the Users page shows a banner and drops its Add/Edit actions), and password changes and resets are blocked — a password changed locally would be silently reverted by the next push, so change it on the primary or through the cloud portal. Sites, roles, and notification profiles are likewise locked on a managed peer; access groups and holiday calendars lock only while the primary is actually pushing them (its Door access toggle is on) — otherwise they stay editable site-local. Visitors are the exception: they're site-local by design, so a managed peer can issue and revoke visitor PINs at any time. Make all other changes on the primary — they arrive automatically.
- Not configured — sync is off; the page explains how to enable it.
Provisioning
GEM Cloud tenant (automatic)
When multiple GEM servers belong to one GEM Cloud tenant, enable account sync for the tenant in the cloud admin. Every member server is then provisioned automatically from its signed tunnel binding — the tenant sync key, the server's role (source or managed), and the current peer list arrive on the next update check. There are no keys to copy between sites.
Pushes travel through the cloud relay and are sealed end-to-end with AES-256-GCM under the tenant key — the relay only carries opaque bytes and can neither read nor forge account data. Sealed payloads carry a timestamp and sequence number, so replays and stale pushes are rejected, and a server provisioned this way refuses plaintext pushes outright. When the tenant key rotates, the previous key generation stays acceptable for a 30-minute grace window so peers that haven't polled for the new key yet aren't cut off mid-rotation.
gem.json (direct / VPN deployments)
Sites that reach each other directly can instead configure peer_sync in gem.json: a shared sync_key, enabled: true on the source, managed: true on each peer. Pushes go straight to each peer site's URL (from Sites) authenticated by the shared key. Cloud-tenant provisioning takes precedence when both are configured.
What gets synced
A push carries users (username, name, email/SMS, enabled state, roles, sites, session timeout, 2FA flag, notification profile, and the password hash), roles, sites, notification profiles, and cloud login sessions (below). Changes push immediately as they happen; a full sync runs at startup, whenever a new peer joins the tenant, and on demand.
Records cross the wire keyed by name, never by numeric id — ids differ between databases. A user's notification profile travels as the profile's name and is re-linked to the matching local profile on the receiving side.
The site registry converges automatically on a cloud tenant, and the tenant's member list in GEM Cloud is its source — not the primary's own site table. When sync activates, the primary renames its own This Server row to its canonical installation name, creates a site row for any tenant peer that doesn't have one — named the same way — so users scoped to that site can log in, then pushes the tenant's sites: its own row plus one per peer. Each row carries the installation ID of the server it describes, and that ID (not the name) is what matches rows across servers: rename a server in GEM Cloud and its row is renamed everywhere — mode links and user site memberships intact — instead of a second row appearing under the new name. A receiving peer recognizes its own row by its installation ID (or, from a primary that predates this, by that canonical name) and applies it onto its local This Server entry, renaming it if needed (user site memberships follow the rename on every server), rather than creating a duplicate; a push never deletes a peer's own site row, sets a URL on it, or lets a row under any other name overwrite it.
A site row added by hand on the primary that isn't a member of the tenant stays on the primary and is not pushed. Rows like that already on peers from earlier versions are left in place.
Cloud login sessions
A login through GEM Cloud is honoured on every site of the tenant. The cloud portal verifies the password and second factor against the primary site once; the primary then mints the UI session, records it, and replicates it — sealed, like everything else — to every peer before the browser is sent on. Whichever site the browser lands on first redeems the handoff, and every later site switch is an ordinary session check against a session that site already knows. One login, one 2FA code, every site.
The portal also keeps a re-entry grant for the session it was handed, for as long as its own sign-in lasts. Whenever the browser lands on a site — a site switch, a reload, a new day — the portal asks that site for a fresh handoff on the same session before the page loads, so a browser that has lost its stored session (a cleared browser, a phone that purged its storage, a session that timed out on one site) is signed back in without a prompt. The grant is replicated with the session and dies with it: signing out on the primary, disabling the account, or the session ageing out all end it everywhere.
A few things follow from how this works:
- Remote logins replicate; local ones don't. A login through the cloud always does — through the portal's handoff, or at a site's own login screen reached over the cloud, which on the primary is recorded and replicated the same way. A login made on the LAN stays on that site: a local login may have skipped 2FA under a role's local bypass, and a session that never proved a second factor must not turn into a remote session somewhere else. A remote login at a peer's login screen stays on that peer too, since peers cannot push. Visitor accounts are site-local and never replicate.
- The browser keeps one session per site. Every site of the tenant is served from the same cloud address, and the app used to keep a single stored session for it — so a login on one site overwrote every other site's, and each switch prompted again. Each controller now names itself to the page, and the app stores a session per site, so a login on one site never disturbs another.
- Signing out on the primary signs out everywhere. The revocation is pushed to every peer that is online at the time, and any browser still connected there is dropped at once. Signing out on a peer signs out that peer only; the browser forgets the session, so the other sites are simply never asked for it again. Disabling an account or changing its password already reaches every site through account sync and ends the session there as well.
- Replicated sessions age out of the table after a year (
tenant_session_daysingem.jsonto change it per site). Ageing out is not a logout: a site the browser has already visited keeps its own session for as long as the user's session timeout allows. It only means a site the browser has never visited will ask for a login once after that. The user's session timeout (Users) applies on every site independently, sliding with activity there; set it to zero for cloud users who should stay signed in. - Peers that are offline catch up on the next full sync, which carries every session that is still adoptable. A site that comes back online after a logout it never heard about keeps that session until its own timeout runs out.
Two toggles on the source control the optional payloads:
- Door access (PINs, RFID, duress PINs, access groups, holiday calendars) — on by default. When off, only accounts, roles, passwords, and notification profiles sync — each site keeps its own local door credentials, access groups, and holiday calendars. Credentials are decrypted only for transport inside the sealed payload and re-encrypted with each receiving site's own local key. Access group membership travels as usernames; members the receiving site doesn't have (e.g. unsynced visitors) are dropped from the group there, with a warning in the server log.
- Visitor accounts — off by default: a visitor PIN issued at one site usually shouldn't open doors at another. Local visitors on peers are never disabled by a sync either way.
Arriving changes apply themselves
A push takes effect the moment it lands. The accounts, roles, sites and profiles it writes are reloaded as part of applying it, and they do not appear in the pending-changes badge in the admin top bar — a managed peer has nothing to approve, since the change was made on the primary and has already arrived. The badge on a peer keeps counting only that site's own edits, and Apply All still applies exactly those.
This is the one difference from editing a role or user locally, where the save queues a pending change and you apply it when you're ready.
A full sync disables any enabled non-visitor account on a managed peer that doesn't exist on the primary. Create accounts on the primary — an account created locally on a managed peer is disabled on the next full sync. The account loses its route and UI access as that sync finishes, and any live session it holds is dropped; it is not still authorized until the next restart.
Peers table
On the source, each peer shows its last push, last successful push, and status — OK, no push yet, or the last error (hover for the full message). The page refreshes every 10 seconds.
Sync now
Sync now pushes a full account sync (all users, roles, the tenant's sites, notification profiles, and — when the Door access toggle is on — access groups and holiday calendars) to every peer immediately — useful after enabling sync, changing the toggles, or when a peer that was offline comes back.
Related Documentation
- Users — account management on the source
- Roles — role definitions (synced to peers)
- Notification Profiles — always synced with accounts
- Access Groups — synced with the Door access toggle
- Holiday Calendars — synced with the Door access toggle
- Visitors — site-local guest credentials
- Sites — peer site URLs for direct deployments