What you will build
This tutorial starts with a working login form. You will identify each sign-in, read the result on the server and compare its Device ID with the account’s active session. If a different device signs in, the demo asks whether to sign out the first one. The one-device rule belongs to this example application; ShieldLabs does not impose it on your accounts. You need Node.js 22 or later. Thestarter app runs locally without keys. To try final with real identifications, have a hostname registered under Integration > Domains, its Public Key and Private API Key from Integration > API keys, and HTTPS routing that hostname to your Node server. A customer’s key is not automatically accepted from localhost.
Run the starting application
Clone the public tutorial repository and install onlyaccount-sharing:
http://127.0.0.1:3000 and sign in with demo@example.com / demo-password. The starter has a login form and SQLite sessions, but it does not identify devices. Sign in from another browser: there is no Device ID check. The app stores only disposable teaching data.
Add the integration
Stop the starter server. Follow the changes in order below; thefinal branch contains their complete implementation. To see every line changed, run git diff starter origin/final -- account-sharing from the repository root. origin/final exists immediately after cloning, before you switch branches.
1
1. Configure the example
The Keep the Private API Key on the server. In
.env copied from starter contains no ShieldLabs keys. Add these two lines to your private account-sharing/.env with the values for your registered hostname:final, server/server.js serves /config.js with only the Public Key and serves the installed JS SDK at /vendor/shieldlabs.js. public/index.html loads those scripts before index.js.2
2. Identify each login attempt in the browser
public/shieldlabs.js loads @shieldlabs-ai/js, starts a check when the form first receives focus and queues checks so they do not overlap. The submit handler in public/index.js takes the resulting request ID:3
3. Verify the result on the server
The login route passes The server uses
requestId to server/accounts.js. That file calls verifyIdentification(requestId) from server/shieldlabs.js:@shieldlabs-ai/node and the Private API Key to read History by that exact request ID. It refuses a missing, stale or reused identification, automation, unusable device data and Dangerous traffic before creating a session. A request ID returned to the browser does not by itself prove that the identification reached History.4
4. Compare the active device
Once the password is correct,
server/accounts.js reads the active session from SQLite. Its decision is based on the verified Device ID:server/db.js stores the Device ID with each session and records used request IDs. The confirmation button in public/index.js sends signOutOtherDevice: true. A page that is already signed in checks /api/session and shows when another device ended its session. The signed-in account is sent to later checks as a hashed User HID; the raw email is not passed to the browser SDK.5
5. Run the completed app
Switch to the completed version and reinstall that folder’s dependencies:Serve the Node process through HTTPS on the hostname registered for your keys. The process listens on
127.0.0.1:3000 behind your reverse proxy. Keep the .env private and check that /config.js exposes only the Public Key.Follow the integration code
The complete, runnable source is in the account-sharing application. Compare thestarter and final versions of these files:
- Browser helper: loads the installed SDK, serializes checks and returns a request ID.
- Server verification: reads real History, checks the matching ID, rereads delayed results and rejects unusable or replayed checks.
- Action routes: passes the action to this example’s business modules. These modules store the decision in this app’s own database.
Try the completed application
- On your registered HTTPS hostname, sign in with
demo@example.com/demo-passwordon one device. Expect Signed in as demo@example.com. - On a different device, use the same demo account. Check that its actual Device ID differs from the first device in History; clearing cookies alone is not evidence of a different device. The app should show This account is signed in on another device and offer Sign out the other device and sign in here.
- Confirm. The second device becomes signed in. The first device should show that it was signed out after the next
/api/sessioncheck. - If you want to repeat the demonstration, use Reset demo DB when
DEMO_ALLOW_RESET=1. This resets this example’s teaching state, not ShieldLabs History.
Check your result
Check one of your test attempts in History using its request ID. Confirm that the Device ID used for the first sign-in is the one stored for that session; for the second device, the ID must differ. Without a History row, the server should refuse the action. A reused request ID should not authorize another sign-in. Runnpm run check and npm test in account-sharing to check the source and the example’s local decision rules. These commands use local test data and do not send another identification.
Allow more than a minute between real checks. A private window may still be identified as the same device; use the values you actually observe.