# Remote MCP Device Authentication and OAuth Flow in DesktopCommanderMCP

> Learn how DesktopCommanderMCP secures remote devices with OAuth 2.0 Device Authorization Grant and PKCE. Understand device codes and token polling for secure WebSocket commands.

- Repository: [Eduard Ruzga/DesktopCommanderMCP](https://github.com/wonderwhy-er/DesktopCommanderMCP)
- Tags: how-to-guide
- Published: 2026-07-10

---

**DesktopCommanderMCP authenticates remote devices using the OAuth 2.0 Device Authorization Grant with PKCE, generating device codes for user approval before polling for access tokens that enable secure WebSocket command channels.**

DesktopCommanderMCP enables cross-machine control through its Remote MCP (Multi-Computer Protocol) feature. The system implements a secure **device authentication** flow using OAuth 2.0 standards to verify remote machine identity before establishing command channels. This process, defined in [`src/remote-device/device-authenticator.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/remote-device/device-authenticator.ts), creates an authenticated session that subsequent remote operations use to authorize requests.

## The OAuth 2.0 Device Authorization Flow

The Remote MCP feature implements the **OAuth 2.0 Device Authorization Grant** (device-code flow) with PKCE (Proof Key for Code Exchange) to securely link client machines without requiring direct user credentials on the remote device.

### PKCE Generation and Security

When initiating a remote session, the client generates cryptographically secure PKCE parameters using the `generatePKCE` function. This creates a random **code verifier** and its SHA-256 **code challenge**, preventing authorization code interception attacks during the device flow.

### Requesting the Device Code

The client sends a `POST /device/start` request to the MCP server with:

- `client_id`: Set to `mcp-device`
- `code_challenge`: The SHA-256 PKCE challenge
- `scope`: Requested permissions (specifically `mcp:tools`)
- Device metadata including hostname, type, and ID

The server responds with a **device code** (for polling), a **user code** (for display), and a `verification_uri` where the user completes authorization.

## User Authorization and Token Polling

### The Authorization Interface

The client automatically opens the complete verification URL using `open(deviceAuth.verification_uri_complete)` and displays the short user code. The user must visit this URL in any browser, sign in if necessary, and approve the specific device requesting access.

### The Polling Mechanism

While awaiting user approval, the client executes a polling loop via `POST /device/poll`, sending the device code, client ID, and original **code verifier**. According to the implementation in [`src/remote-device/device-authenticator.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/remote-device/device-authenticator.ts), the server may return several states:

- **`authorization_pending`**: Continue polling at the specified interval
- **`slow_down`**: Increase polling intervals to reduce server load
- **`access_token`**: Authentication succeeded, returning the token plus optional `refresh_token` and `device_id`

If the polling exceeds the expiration time or encounters unrecoverable errors, the client logs the failure via `captureRemote` and throws an authorization error.

## Establishing the Remote Channel

Once the OAuth flow completes successfully, the `DeviceAuthenticator` returns an `AuthSession` object containing the `access_token`. This session passes to **[`src/remote-device/remote-channel.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/remote-device/remote-channel.ts)**, which constructs a persistent communication channel using WebSocket or Server-Sent Events (SSE).

The `RemoteChannel` class includes the `Authorization: Bearer <access_token>` header in all requests, enabling the server to:

- Validate the device identity against the issued token
- Enforce scope-based permissions (`mcp:tools`)
- Maintain secure bidirectional communication for commands, file previews, and tool output

## Code Implementation Examples

### Starting the Authentication Flow

```typescript
import { DeviceAuthenticator } from './remote-device/device-authenticator';
import { RemoteChannel } from './remote-device/remote-channel';

const authenticator = new DeviceAuthenticator('https://mcp.example.com');

authenticator.authenticate()
  .then(session => {
    console.log('Authenticated:', session.access_token);
    const channel = new RemoteChannel(session.access_token);
    return channel.connect();
  })
  .then(() => console.log('Remote channel ready'))
  .catch(err => console.error('Authentication failed:', err));

```

### Polling Implementation Details

The `pollForAuthorization` method in [`device-authenticator.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/device-authenticator.ts) handles the retry logic:

```typescript
private async pollForAuthorization(
  deviceAuth: DeviceAuthResponse,
  codeVerifier: string,
): Promise<AuthSession> {
  const interval = (deviceAuth.interval || 5) * 1000;
  const maxAttempts = Math.floor(deviceAuth.expires_in / (deviceAuth.interval || 5));
  
  for (let attempt = 0; attempt < maxAttempts; ++attempt) {
    await this.sleep(interval);
    
    const resp = await fetch(`${this.baseServerUrl}/device/poll`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        device_code: deviceAuth.device_code,
        client_id: CLIENT_ID,
        code_verifier: codeVerifier,
      }),
    });
    
    const data: PollResponse = await resp.json();
    if (resp.ok && data.access_token) {
      return { 
        access_token: data.access_token, 
        refresh_token: data.refresh_token ?? null, 
        device_id: data.device_id 
      };
    }
    if (data.error === 'authorization_pending') continue;
    if (data.error === 'slow_down') await this.sleep(interval);
  }
  throw new Error('Authorization timeout');
}

```

## Key Implementation Files

The Remote MCP authentication system spans several critical files in the DesktopCommanderMCP repository:

- **[`src/remote-device/device-authenticator.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/remote-device/device-authenticator.ts)**: Implements the complete OAuth 2.0 device-code flow with PKCE and polling logic
- **[`src/remote-device/remote-channel.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/remote-device/remote-channel.ts)**: Manages the authenticated WebSocket/SSE connection using Bearer token authorization
- **[`src/remote-device/device.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/remote-device/device.ts)**: Represents the remote device object and stores authenticated session state
- **[`src/remote-device/desktop-commander-integration.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/remote-device/desktop-commander-integration.ts)**: Bridges the UI with the remote-device authentication flow
- **[`src/utils/capture.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/capture.ts)**: Provides telemetry logging for authentication events via `captureRemote`

## Summary

DesktopCommanderMCP secures remote machine access through a standards-compliant OAuth 2.0 implementation:

- **PKCE-enhanced security**: SHA-256 code challenges prevent authorization code interception during the device flow
- **Polling-based activation**: The client polls `POST /device/poll` until receiving an `access_token` or encountering a timeout
- **Scoped permissions**: Tokens enforce `mcp:tools` scope restrictions on remote operations
- **Bearer token transport**: The `RemoteChannel` includes `Authorization: Bearer` headers to maintain session state across WebSocket connections
- **Error resilience**: Unrecoverable authentication failures trigger `captureRemote` logging and clear error propagation

## Frequently Asked Questions

### What OAuth grant type does DesktopCommanderMCP use for remote devices?

DesktopCommanderMCP implements the **OAuth 2.0 Device Authorization Grant** (RFC 8628), often called the device-code flow. This grant type is designed for input-constrained devices like remote servers that cannot easily accept user credentials directly, combined with PKCE (RFC 7636) for additional security against code interception attacks.

### How long does the device authorization polling continue?

The polling duration depends on the `expires_in` value returned by the `POST /device/start` endpoint. The `pollForAuthorization` method calculates `maxAttempts` by dividing `expires_in` by the polling `interval` (defaulting to 5 seconds). If the user does not authorize the device within this window, the client throws an "Authorization timeout" error.

### What happens to the access token after authentication completes?

The `access_token` is stored in an `AuthSession` object returned by the `DeviceAuthenticator`. This session is then passed to the `RemoteChannel` constructor, which includes the token in the `Authorization: Bearer` header for all subsequent WebSocket or SSE connections. The token enables the MCP server to identify the specific remote device and enforce scope-based access controls on tool executions.

### Is the user code displayed securely in DesktopCommanderMCP?

Yes. The client displays the **user code** locally in the terminal or UI while simultaneously attempting to open the `verification_uri_complete` URL automatically via the `open` system command. This two-factor approach ensures the user code is both visible for manual entry and pre-populated in the browser, reducing phishing risks while maintaining usability.