ProficientNowTechRFCs

RFC: Managed Concurrent Sessions & Device Tracking

RFC: Managed Concurrent Sessions & Device Tracking

  • Authors: - Prathik Shetty(@pshettydev)
  • Date: 2026-01-13
  • Status: Accepted

Abstract

This RFC outlines the implementation of a robust device tracking and session management system for the PNow ATS. The system transitions from a potential "Single Active Device" model (which although defined in schema but not in use by the application) to a "Managed Concurrent Sessions" model. This approach allows users to access the platform from multiple devices (e.g., laptop and mobile) simultaneously while strictly tracking device identity, IP addresses, and geographical locations for security auditing and anomaly detection.

Motivation

In modern recruitment workflows, users frequently switch contexts between desktop applications and mobile devices. Enforcing a strict "single active session" policy (where logging in on a new device or browser, logs out the desktop) creates significant friction ("login fatigue") and degrades the user experience.

However, security remains paramount given the sensitive PII (candidate data) handled by the ATS. We needed a solution that:

  1. Enhances UX: Supports multi-device productivity without constant re-authentication.
  2. Improves Security: Provides deep visibility into who is accessing the system, from where, and on what device.
  3. Enables Auditing: Maintains a historical record of access locations and IPs to detect suspicious patterns (e.g., impossible travel, unknown devices).

Approaches

Evaluated three primary strategies for session management:

1. Single Active Device (Strict Session Management)

  • Concept: A user can only be logged in on one device at a time. A new login invalidates the previous session token.
  • Pros: Minimizes attack surface; prevents account sharing; simplifies backend logic (no sync needed).
  • Cons: Poor UX for modern multi-device users; frustrates users switching between contexts.

[!NOTE]
This is considered the end goal for high-security environments. However, implementing this immediately would introduce excessive friction. We chose to start with a more flexible approach (Option 3) to gather usage data and provide a smooth initial experience, while building the infrastructure (device tracking) that could enable this strict mode in the future.

2. Unrestricted Multi-Device Access (Earlier implemented approach)

  • Concept: Users can log in from as many devices as they want with no specific tracking.
  • Pros: Maximum convenience; zero friction.
  • Cons: High security risk; rampant account sharing (revenue leakage); difficult to detect compromised credentials until it's too late.

3. Managed Concurrent Sessions (Auditable Security) - CHOSEN (Initial Implementation)

  • Concept: Allow multiple sessions but rigorously track and fingerprint each device. Differentiate between known devices and new ones. Log location history per device.
  • Pros: Balances UX and Security. Allows productivity while enabling security features like "Revoke Device," "New Device Alerts," and "Suspicious Location Detection."
  • Cons: Higher implementation complexity (requires device fingerprinting and location history schema).

[!IMPORTANT] Strategic Decision: This approach was selected to prioritize user adoption and smooth workflow integration. By implementing robust tracking first, we establish the necessary audit trails and device identity infrastructure. This leaves room to enforce stricter policies (like limiting the number of concurrent sessions or moving to Single Active Device) in the future without architectural rework.

Proposal

We implemented Option 3: Managed Concurrent Sessions. This involves changes across the full stack, from the frontend client to the database schema.

1. Architecture Overview

  1. Frontend Identity: The client generates a persistent unique identifier (x-device-id) stored in local storage. This ID, along with the User Agent, is sent with every API request.
  2. API Gateway: Acts as the ingress point. It extracts the x-device-id, User-Agent, and Client IP (request-ip). It proxies these details to the Authentication Service during Login and Token Refresh events.
  3. Authentication Service: The source of truth. It resolves the IP to a physical location (geoip-lite) and updates the database. It maintains a registry of UserDevices and a history of UserDeviceLocations.

2. Schema Changes

The database schema (prisma/tenants/schema/users/users.prisma) was updated to support history tracking and removed restrictive unique constraints.

  • UserDevice:
    • Removed unique constraint on user_id to allow multiple devices per user.
    • Added current_ip (@db.Inet) for quick access to the last known IP.
    • Added device_metadata to store User Agent details.
  • UserDeviceLocation:
    • Removed unique constraints on device_id to allow a one-to-many relationship (Device -> Locations).
    • Added ip_address (@db.Inet) and created_at timestamps to form an immutable location history log.
model UserDevice {
  id                      String   @id @default(uuid()) @db.Uuid
  unique_device_signature String
  user_id                 String   @db.Uuid
  current_ip              String?  @db.Inet
  // ... relations
}
 
model UserDeviceLocation {
  id         String   @id @default(uuid()) @db.Uuid
  lat        Float
  long       Float
  ip_address String?  @db.Inet
  created_at DateTime @default(now())
  // ... relations
}

3. Implementation Details

Frontend (axios interceptors)

A shared Axios interceptor (apps/frontend/web/src/utils/api/axiosInstance.ts) manages the device identifier. It checks localStorage for an existing ID or generates a UUID, then injects it into request headers:

'x-device-id': getDeviceId(),

The same interceptor handles 401 refresh retries for API gateway calls (and avoids retrying /auth/refresh itself).

Backend (auth-service)

A new trackDevice method was implemented in AuthenticationService:

  1. Upsert Device: Updates last_accessed_at and current_ip.
  2. Location Resolution: Uses geoip-lite to resolve coordinates from the IP.
  3. History Logging: If the IP has changed since the last record, a new UserDeviceLocation entry is created.

Additional updates:

  • Cookie parsing is enabled (cookie-parser) so refresh-token guards can read cookies.
  • Device metadata now stores structured user-agent details (object entries) instead of raw strings.
  • New endpoints expose device lists and device history for the signed-in user.

API Gateway

The Gateway proxies refresh calls to the Auth Service, forwarding x-device-id, user-agent, and client IP, then extracts set-cookie from the response and re-sets access/refresh cookies for the client. It also exposes device list/history endpoints backed by auth-service. Login proxying remains unchanged.

4. Security Considerations

  • IP Spoofing: We utilize request-ip and x-forwarded-for headers to correctly identify client IPs behind load balancers.
  • Trust: While x-device-id is client-generated, combining it with signed JWTs and IP history creates a strong enough fingerprint for "Authorized Device" tracking.