Skip to main content

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. The starter 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 only account-sharing:
Open 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; the final 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 .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:
Keep the Private API Key on the server. In 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:
The browser sends the request ID, not a Risk Score or a Private API Key. The request ID is a reference to the result the server will retrieve.
3

3. Verify the result on the server

The login route passes requestId to server/accounts.js. That file calls verifyIdentification(requestId) from server/shieldlabs.js:
The server uses @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 the starter and final versions of these files:
  1. Browser helper: loads the installed SDK, serializes checks and returns a request ID.
  2. Server verification: reads real History, checks the matching ID, rereads delayed results and rejects unusable or replayed checks.
  3. Action routes: passes the action to this example’s business modules. These modules store the decision in this app’s own database.
The example’s session table and policy are for learning. Adapt the action and account rules to your own product before using them for customer sign-ins.

Try the completed application

  1. On your registered HTTPS hostname, sign in with demo@example.com / demo-password on one device. Expect Signed in as demo@example.com.
  2. 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.
  3. Confirm. The second device becomes signed in. The first device should show that it was signed out after the next /api/session check.
  4. 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.
If a check is rate limited, stop and follow the troubleshooting steps. Do not run parallel checks or change IPs to get around a limit.

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. Run npm 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.

Adapt it to your product

This example is a starting point, not a production-ready authorization system. Bind each action to an authenticated session where appropriate, authorize administration screens, persist state and atomically consume request IDs across all server instances. Review legitimate shared-device behavior before applying a device-based restriction. See Acting on results.