6. SimConnect device authentication
- Date: 2026-05-25
- Status: Proposed
Context
Our software solution is composed of three projects:
- A backend REST API that owns user identity and issues authentication tokens (JWT).
- A web client through which the end user can already authenticate against the backend.
- SimopsConnect a Windows console application that runs without meaningful UI and without direct end-user interaction by design.
Today, only the web client supports an interactive authentication flow. The SimopsConnect application has no authenticated identity, which limits what it can do against the backend on behalf of a user.
The desired behavior is that SimopsConnect also operates as an authenticated user, with the authentication experience being as transparent as possible.
Constraints that shape the decision:
- The web client and the SimopsConnect application are not guaranteed to run on the same host or even the same network. A solution that assumes co-location (loopback callbacks, shared filesystem, local IPC) cannot be the primary mechanism.
- SimopsConnect application has no usable interactive UI: it cannot host a login form, a browser control, or a rich dialog.
- The end user should not be expected to configure networking infrastructure (open inbound firewall ports, set up port forwarding, install certificates for a local HTTPS endpoint, etc.).
- The backend is reachable by both clients (it is the API they consume) and can be extended with new endpoints.
- The solution must be safe to operate in heterogeneous environments (corporate networks, NAT, restrictive egress proxies, multiple machines per user).
An initial idea was for the web client to push the user's credentials (JWT) directly to an HTTP service hosted by SimopsConnect. This approach was investigated and discarded because it requires SimopsConnect to accept inbound connections, which forces firewall configuration, host/port discovery, and local TLS, exactly the friction we want to avoid.
Decision
We will implement console-application authentication using the OAuth 2.0 Device Authorization Grant (RFC 8628), with the backend acting as the authorization server and the SimopsConnect acting as the device client. The web client, where the user is already authenticated, plays the role of the user-agent that approves the device.
Key properties of the chosen design:
- The SimopsConnect only initiates outbound HTTPS calls to the backend. It never listens for inbound connections, so no firewall changes, port forwarding, or local TLS are required on the user's machine.
- The backend is the single intermediary between the two clients. The web client and the SimopsConnect never communicate directly with each other and therefore do not need to share a host or a network.
- The user's interaction surface stays in the browser, where the web client already provides an authenticated session and a suitable UI. The console only needs to display a short user code as text.
- The SimopsConnect receives its own pair of tokens (access token and refresh token), distinct from the web client's session. These tokens have their own lifecycle and can be revoked independently.
Flow summary
- The console starts and calls
POST /auth/device/starton the backend. The backend returns adevice_code(kept secret by the console), a short human-readableuser_code, averification_uri, a pollinginterval, and anexpires_in. - The console displays the verification URI and the user code on its standard output and begins polling
POST /auth/device/pollwith thedevice_code. - The user opens the verification URI in the web client (where they are already authenticated), enters the
user_code, and confirms. - The web client calls
POST /auth/device/approvewith theuser_code, using its existing user JWT as authorization. - The backend associates the
device_codewith the approving user's identity. - On the next poll, the backend responds with an
access_tokenand arefresh_tokenissued specifically for SimopsConnect. - SimopsConnect stores the refresh token in OS-protected storage (DPAPI on Windows) and uses it for silent re-authentication on subsequent runs.
Security requirements
- SimopsConnect receives tokens distinct from the user's web session JWT. The web client's JWT is never transmitted to or stored by SimopsConnect.
- Console tokens have their own audience and scopes, so authorization decisions can differ between the two clients and revocation is independent.
- The
device_codeis bound to a client-generated secret (PKCE-style proof-of-possession) so that intercepting the shortuser_codeis not sufficient to retrieve the tokens. - The
user_codeis short, high-entropy, single-use, and short-lived (a few minutes). - The console stores the refresh token using OS-protected storage (DPAPI on Windows) and applies refresh token rotation so that re-authentication on subsequent runs is silent and non-interactive.
Alternatives considered
A. Web client pushes the JWT directly to an HTTP endpoint hosted by SimopsConnect (initial proposal)
SimopsConnect would expose a local HTTP service; the web client would POST the user's JWT to it.
- Rejected. Requires the console to accept inbound connections, which forces firewall configuration, host/port discovery, and local TLS. Breaks immediately when the two clients are not on the same host or network. Also conflates the web session JWT with the console's identity, complicating revocation and scoping.
B. Loopback redirect OAuth 2.0 flow (RFC 8252)
SimopsConnect opens a local browser, listens on http://127.0.0.1:<random_port>, and receives the authorization code via redirect.
- Rejected as the primary mechanism. Assumes a usable local browser and that the console and browser run on the same machine, which violates the stated constraints. It also still requires a local listener, which competes with the original concern about local network configuration. Could be considered as a secondary mode for on-host scenarios, but adds complexity without removing the need for the device flow.
C. Pre-provisioned long-lived API key / enrollment token
The user generates a long-lived API key from the web client and pastes it into the console's configuration file at first run.
- Partially adopted as a fallback option. It is well-suited to fully non-interactive deployments (e.g. scheduled jobs, headless installations). However, it requires an explicit manual setup step, is harder to rotate, and offers a weaker security posture than short-lived tokens with rotation. It will be offered as an optional mode for unattended deployments but is not the default.
D. Resource Owner Password Credentials grant
SimopsConnect prompts the user for username and password and exchanges them at the backend.
- Rejected. Discouraged by current OAuth 2.0 best practice (OAuth 2.0 Security BCP). Incompatible with SSO, MFA, and federated identity providers. Also requires the console to handle plaintext credentials, which we explicitly want to avoid.
E. Direct SimopsConnect ↔ web client communication via a relay or messaging service
Use a third-party relay (WebSocket gateway, message broker) to bridge the two clients.
- Rejected. Adds a new external dependency for a problem the existing backend can solve. Increases the attack surface and operational footprint without addressing any constraint the device flow does not already address.
Consequences
Pros
- No network configuration required on the user's machine: SimopsConnect only makes outbound HTTPS calls, which already work wherever the API does.
- Topology-independent: The web client and SimopsConnect can run on different machines, networks, or operating systems.
- Minimal user interaction: A single action, entering a short code in an already-open authenticated browser session, is enough to pair the console. Subsequent runs are silent.
- Standards-based: The flow is RFC 8628 and is well understood, well documented, and supported by mature libraries on both .NET and the web stack.
- Independent token lifecycle. Revoking the SimopsConnect's access does not log the user out of the web client and vice versa. Scopes can be tightened for the console.
- Backward-compatible. The existing web authentication flow is unchanged.
Cons
- Backend surface area increases: Three new endpoints (
/auth/device/start,/auth/device/poll,/auth/device/approve), a new approval page in the web client, and persistent state for pending device codes are required. - First-run is not fully silent: The user must perform one explicit pairing action the first time the console runs on a given machine. Mitigated by long-lived refresh tokens with rotation so this is a one-time cost per machine, and by offering the pre-provisioned key (alternative C) for fully unattended scenarios.
- New secret to protect on the console host: The refresh token must be stored with OS-level protection (DPAPI on Windows). Loss of that secret implies re-pairing.
Neutral
- A short-lived
device_code↔ user binding must be stored server-side. This can live in the existing relational store or in a short-TTL cache; both are acceptable.
Implementation notes
- Backend: add
/auth/device/start,/auth/device/poll,/auth/device/approve. State transitions for a device code arepending → approved → consumed, plus terminalexpiredanddenied. Token issuance onconsumedproduces console-scoped access and refresh tokens. - Web client: add a
/linkroute that accepts auser_code, validates the user's session, and calls/auth/device/approve. - Console (.NET): implement the polling client, store refresh tokens via DPAPI, and implement refresh token rotation. Expose an optional pre-provisioned-key mode (alternative C) for unattended deployments.
- Observability: log device-code lifecycle events (issued, approved, consumed, expired, denied) with correlation IDs for support and audit.
Open questions
- Exact lifetime of the access and refresh tokens issued to the SimopsConnect.
- Whether to surface paired devices in the web client so the user can review and revoke them.
- Whether to enforce a maximum number of concurrent paired devices per user.
References
- RFC 8628: OAuth 2.0 Device Authorization Grant
- RFC 8252: OAuth 2.0 for Native Apps
- OAuth 2.0 Security Best Current Practice (draft-ietf-oauth-security-topics)