Remote MCP Device Authentication and OAuth Flow: Complete Implementation Guide

Remote MCP uses the OAuth 2.0 Device Authorization Grant to authenticate headless devices through a secure polling mechanism where users authorize access via a separate browser session.

The wonderwhy-er/DesktopCommanderMCP repository implements a robust authentication system for remote devices using the OAuth 2.0 Device Authorization Grant. This Remote MCP device authentication flow enables secure access for headless or input-constrained devices by delegating user interaction to a secondary browser session. According to the source documentation in src/remote-device/README.md, the implementation follows the official OAuth 2.0 specification to ensure strong security guarantees while maintaining a simple user experience.

How the OAuth 2.0 Device Flow Works in Remote MCP

The Remote MCP device authentication process follows the standard OAuth 2.0 Device Authorization Grant through five distinct phases. Each phase ensures that devices without browsers or input capabilities can securely obtain access tokens.

  1. Device initiates login – The client sends a POST /device/code request to the server's device-code endpoint. The response includes a device code, user code, and verification URL.
  2. User authorizes – The user opens the verification URL on any browser, enters the short-lived user code, and signs in with their account.
  3. Device polls for token – While the user authorizes, the client repeatedly polls POST /token with the device code at the specified interval (typically every 5 seconds). Once authorization completes, the server returns an access token.
  4. Secure channel establishment – The client stores the access token locally in encrypted storage for subsequent API calls.
  5. Token renewal – If provided, the client uses a refresh token to silently obtain new access tokens before expiration.

Client-Side Implementation: Requesting Device Codes

In src/auth/deviceAuth.ts, the client-side logic handles the initial device code request and token polling. The startDeviceAuth() function initiates the flow, while pollForToken() manages the polling loop.

Initiating the Authentication Flow

The following TypeScript implementation demonstrates how the Remote MCP client requests a device code and begins the polling process:

import { startDeviceAuth } from './auth/deviceAuth';

async function initRemoteMcp() {
  // Trigger the device‑code request
  const { device_code, user_code, verification_uri, expires_in, interval } =
    await startDeviceAuth();

  console.log(`Visit ${verification_uri} and enter code: ${user_code}`);

  // Poll for the token
  const token = await pollForToken(device_code, interval);
  // Store token securely (e.g., encrypted local storage)
  await saveToken(token);
}

Server-Side Implementation: Handling Device Codes and Tokens

The server implementation in src/server/routes/device.ts manages the device code lifecycle and token issuance. This includes generating unique codes, validating user authorization status, and issuing bearer tokens.

Generating Device and User Codes

When a device initiates authentication, the server generates a UUID-based device code and a human-readable user code. The deviceCodeHandler function in src/server/routes/device.ts persists these mappings with expiration timestamps:

import { v4 as uuidv4 } from 'uuid';
import { addDeviceCode } from './store';

export async function deviceCodeHandler(req, res) {
  const deviceCode = uuidv4();
  const userCode = generateHumanReadableCode(); // e.g., “ABCD‑EFGH”
  const verificationUri = `${process.env.BASE_URL}/device`;

  // Persist the mapping with an expiration timestamp
  await addDeviceCode({
    deviceCode,
    userCode,
    expiresAt: Date.now() + 10 * 60 * 1000, // 10 min
  });

  res.json({
    device_code: deviceCode,
    user_code: userCode,
    verification_uri: verificationUri,
    expires_in: 600,
    interval: 5,
  });
}

Processing Token Polling Requests

The tokenHandler function validates device codes and returns access tokens once the user completes authorization. Stored in src/server/routes/device.ts, this endpoint handles the polling requests from waiting devices:

import { getDeviceCodeEntry, generateAccessToken } from './store';

export async function tokenHandler(req, res) {
  const { device_code } = req.body;
  const entry = await getDeviceCodeEntry(device_code);

  if (!entry) return res.status(400).json({ error: 'invalid_device_code' });
  if (Date.now() > entry.expiresAt) return res.status(400).json({ error: 'expired_token' });
  if (!entry.authorized) return res.status(428).json({ error: 'authorization_pending' });

  const accessToken = generateAccessToken(entry.userId);
  res.json({ access_token: accessToken, token_type: 'Bearer', expires_in: 3600 });
}

Secure Token Storage and Session Management

After obtaining an access token, the Remote MCP client stores credentials securely using encrypted local storage. The saveToken() function ensures that bearer tokens remain accessible for authenticated API calls while protecting against local extraction attacks. If the server issues a refresh token during the tokenHandler exchange, the client can silently renew sessions without requiring repeated user authorization.

Key Files in the DesktopCommanderMCP Repository

The following source files define the end-to-end authentication mechanism in the wonderwhy-er/DesktopCommanderMCP repository:

Summary

Remote MCP device authentication implements the OAuth 2.0 Device Authorization Grant to securely connect headless devices to the DesktopCommanderMCP service. Key implementation details include:

  • The device flow separates user interaction from device authentication by using short-lived user codes and verification URLs
  • startDeviceAuth() in src/auth/deviceAuth.ts initiates the flow while pollForToken() handles the polling loop
  • Server endpoints in src/server/routes/device.ts manage code generation, validation, and token issuance
  • Tokens are stored in encrypted local storage with support for silent renewal via refresh tokens
  • The 10-minute expiration window for device codes ensures security while allowing adequate time for user authorization

Frequently Asked Questions

What is the OAuth 2.0 Device Authorization Grant?

The OAuth 2.0 Device Authorization Grant is a protocol designed for devices that lack browsers or input methods, such as IoT devices or CLI tools. It allows these devices to obtain access tokens by having users complete authorization on a separate device with a browser, such as a smartphone or laptop.

How long does the device code remain valid in Remote MCP?

According to the implementation in src/server/routes/device.ts, device codes expire after 10 minutes (600 seconds). The expiresAt timestamp is set to Date.now() + 10 * 60 * 1000 when the code is generated, providing users with sufficient time to complete authentication.

What happens if the user doesn't authorize the device before expiration?

If the user fails to authorize the device before the 10-minute window closes, the tokenHandler returns an expired_token error with HTTP status 400. The device must then restart the authentication flow by requesting a new device code through startDeviceAuth().

Can Remote MCP refresh access tokens without user interaction?

Yes, if the initial token exchange provides a refresh token, the Remote MCP client can silently obtain new access tokens before the current one expires. This keeps the remote device online indefinitely without requiring repeated user authorization, as implemented in the token storage logic of src/auth/deviceAuth.ts.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →