# How AionUi Provides Remote Browser Access with JWT Authentication and WebSockets

> Access browsers remotely with AionUi. Discover how it uses JWT authentication and WebSockets for secure, seamless remote browser access.

- Repository: [OfficeAI/AionUi](https://github.com/iofficeai/aionui)
- Tags: how-to-guide
- Published: 2026-02-19

---

**AionUi enables secure remote browser access by running in remote mode with CORS-configured LAN access, JWT-based authentication via HTTP-only cookies and Authorization headers, and WebSocket connections validated on every handshake and heartbeat.**

AionUi's WebUI architecture supports both local development and production remote access scenarios. When configured for remote access, the application exposes a secure web interface accessible from any device on the same network, protected by stateless JWT authentication that applies uniformly to both REST API endpoints and real-time WebSocket channels.

## Enabling Remote Mode and Network Configuration

AionUi operates in two distinct networking modes controlled by the `allowRemote` parameter. In local mode (default), the server binds to `127.0.0.1` and accepts connections only from the same machine. When remote mode is activated—either via CLI flag (`npm start -- --remote`) or programmatically—the server binds to `0.0.0.0` and calculates the host's LAN IP address to facilitate cross-device access.

In [`src/webserver/index.ts`](https://github.com/iOfficeAI/AionUi/blob/main/src/webserver/index.ts), the `startWebServerWithInstance` function orchestrates this startup process. It calls `SERVER_CONFIG.setServerConfig` to persist the remote mode state, invokes `getServerIP` to determine the public-facing address, and prints both localhost and network URLs to the console. This allows users to connect from browsers running on smartphones, tablets, or other computers within the same local network.

## CORS Configuration for Cross-Origin Requests

When `allowRemote` is enabled, the server automatically configures Cross-Origin Resource Sharing (CORS) to permit browser access from the LAN IP address. The `setupCors` function in [`src/webserver/setup.ts`](https://github.com/iOfficeAI/AionUi/blob/main/src/webserver/setup.ts) delegates to `getConfiguredOrigins`, which dynamically constructs the origin string `http://<lan-ip>:<port>` and adds it to the whitelist alongside localhost.

This configuration is critical for modern browser security models. Without explicit CORS headers allowing the LAN origin, browsers would block XHR and fetch requests when accessing the UI from remote devices, even when connected to the same physical network.

## JWT Authentication Implementation

The authentication system centers on JSON Web Tokens generated by `AuthService.generateToken` and returned to clients upon successful login via the `/login` endpoint in [`src/webserver/routes/authRoutes.ts`](https://github.com/iOfficeAI/AionUi/blob/main/src/webserver/routes/authRoutes.ts). The server transmits the JWT through two parallel mechanisms:

- **HTTP-only cookie**: Stored under the name defined by `AUTH_CONFIG.COOKIE.NAME`, providing automatic token transmission for browser-based requests
- **JSON response body**: Available in the `token` field for programmatic clients that manage authentication state manually

This dual-delivery approach ensures compatibility with both browser-based UI interactions and API consumers. The cookie configuration uses secure flags appropriate for the deployment context, while the JSON payload enables mobile applications and scripts to extract the token for header-based authentication.

## Token Extraction and Validation Middleware

All protected routes and WebSocket connections rely on [`TokenMiddleware.ts`](https://github.com/iOfficeAI/AionUi/blob/main/TokenMiddleware.ts) for token extraction and validation. The `TokenExtractor.extract` method inspects incoming requests for the JWT in the following priority order:

1. `Authorization: Bearer <jwt>` header
2. Session cookie (name specified in constants)
3. Explicit rejection of URL query parameters (security hardening)

For WebSocket connections, the `extractWebSocketToken` function performs analogous extraction during the handshake phase. The middleware then invokes `AuthService.verifyToken` for HTTP requests or `AuthService.verifyWebSocketToken` for socket connections, validating the signature, expiration timestamp, and optionally a per-user `jwt_secret`. Invalid tokens result in immediate **403 Forbidden** responses, either as JSON for API routes or HTML error pages for direct browser access.

## WebSocket Connection Management and Security

Real-time communication flows through the `WebSocketManager` class in [`src/webserver/websocket/WebSocketManager.ts`](https://github.com/iOfficeAI/AionUi/blob/main/src/webserver/websocket/WebSocketManager.ts). The connection lifecycle implements rigorous authentication checks:

**Handshake Validation**: Clients first obtain a valid token via the `/api/ws-token` endpoint (which simply echoes the current session JWT), then initiate the WebSocket connection. The server validates the token during the upgrade handshake using the same middleware logic as HTTP routes.

**Ongoing Verification**: The manager runs periodic `checkClients` cycles that validate tokens on every heartbeat tick. If a token expires during an active session, the server emits an `auth-expired` message to the client and terminates the socket connection.

**Protocol Compliance**: Clients can transmit the JWT via the `Authorization` header, cookie mechanism, or the `Sec-WebSocket-Protocol` header during the initial handshake, ensuring compatibility with various WebSocket client implementations.

## Token Refresh and Session Continuity

To maintain long-running remote sessions without forcing re-authentication, AionUi provides the `/api/auth/refresh` endpoint. Clients detect the `auth-expired` WebSocket message or 403 HTTP responses and call this endpoint with their existing (but expired) token to receive a fresh JWT. This mechanism allows continuous remote monitoring and control without interrupting the user workflow.

## Practical Implementation Examples

### Starting the Server in Remote Mode

```bash

# Enable remote access from any device on the LAN

npm run start -- --remote

```

### Authenticating and Storing the JWT

```typescript
async function login(username: string, password: string) {
  const resp = await fetch('/login', {
    method: 'POST',
    credentials: 'include',               // cookie will be set automatically
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ username, password })
  });
  const data = await resp.json();
  if (data.success) {
    const jwt = data.token;               // available in body or cookie
    return jwt;
  }
  throw new Error(data.message);
}

```

### Establishing an Authenticated WebSocket Connection

```typescript
async function openSecureWebSocket() {
  const token = await login('admin', 'password');
  
  const ws = new WebSocket(`ws://${window.location.host}`);
  
  ws.addEventListener('open', () => {
    // Authenticate immediately upon connection
    ws.send(JSON.stringify({ name: 'auth', data: { token } }));
  });
  
  ws.onmessage = (event) => {
    const msg = JSON.parse(event.data);
    if (msg.name === 'auth-expired') {
      console.error('Session expired, refresh required');
    }
  };
}

```

### Refreshing an Expired Token

```typescript
async function refreshToken(oldToken: string) {
  const resp = await fetch('/api/auth/refresh', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ token: oldToken })
  });
  const { token } = await resp.json();
  return token;
}

```

## Summary

- **Remote mode** activates by setting `allowRemote = true` or using the `--remote` CLI flag, binding the server to `0.0.0.0` instead of localhost
- **Dynamic CORS** in [`src/webserver/setup.ts`](https://github.com/iOfficeAI/AionUi/blob/main/src/webserver/setup.ts) automatically whitelists the host's LAN IP address when remote mode is enabled
- **Dual JWT delivery** via HTTP-only cookies and JSON response body ensures compatibility with browsers and API clients
- **Unified validation** through [`TokenMiddleware.ts`](https://github.com/iOfficeAI/AionUi/blob/main/TokenMiddleware.ts) enforces consistent security across REST endpoints and WebSocket connections
- **Continuous verification** via [`WebSocketManager.ts`](https://github.com/iOfficeAI/AionUi/blob/main/WebSocketManager.ts) checks token validity on every heartbeat, emitting `auth-expired` when credentials expire
- **Token refresh** via `/api/auth/refresh` enables seamless session continuity without requiring manual re-login

## Frequently Asked Questions

### How do I access AionUi from my phone when running on my laptop?

Enable remote mode by starting the server with `npm run start -- --remote`. The console will display a network URL containing your laptop's LAN IP address (e.g., `http://192.168.1.5:3000`). Ensure both devices connect to the same Wi-Fi network, then open this URL in your phone's browser. The server automatically configures CORS to accept requests from this origin.

### Why does AionUi reject my JWT when passed as a URL parameter?

The `TokenExtractor` class in [`src/webserver/auth/middleware/TokenMiddleware.ts`](https://github.com/iOfficeAI/AionUi/blob/main/src/webserver/auth/middleware/TokenMiddleware.ts) explicitly ignores URL query parameters for security reasons. Passing tokens in URLs exposes credentials in browser history and server logs. Instead, transmit the JWT via the `Authorization: Bearer` header or rely on the HTTP-only cookie set during login.

### What happens when my WebSocket token expires during an active session?

The `WebSocketManager` validates tokens during its periodic heartbeat checks. Upon detecting an expired token, it sends an `auth-expired` message to the client and immediately closes the connection. Your client application should listen for this message and call the `/api/auth/refresh` endpoint to obtain a new token before reconnecting.

### Can I use the same authentication token for both REST API calls and WebSocket connections?

Yes. AionUi uses identical JWT validation logic for both transport mechanisms. The token obtained from `/login` or `/api/ws-token` works interchangeably in HTTP `Authorization` headers and WebSocket authentication messages. The `AuthService.verifyToken` and `AuthService.verifyWebSocketToken` methods apply the same cryptographic verification and expiration checks.