Claude
Skills
Sign in
Back

understanding-tauri-ipc

Included with Lifetime
$97 forever

Teaches the assistant about Tauri IPC (Inter-Process Communication) patterns including brownfield and isolation approaches for secure message passing between frontend and Rust backend.

Web Dev

What this skill does


# Tauri Inter-Process Communication (IPC)

This skill covers Tauri's IPC system, including the brownfield and isolation patterns for secure communication between frontend and backend processes.

## Overview

Tauri implements Inter-Process Communication using **Asynchronous Message Passing**. This enables isolated processes to exchange serialized requests and responses securely.

**Why Message Passing?**
- Safer than shared memory or direct function access
- Recipients can reject or discard malicious requests
- Tauri Core validates all requests before execution
- Prevents unauthorized function invocation

## IPC Primitives

Tauri provides two IPC primitives:

### Events

- **Direction**: Bidirectional (Frontend <-> Tauri Core)
- **Type**: Fire-and-forget, one-way messaging
- **Best for**: Lifecycle events, state changes, notifications

**Rust (emit to frontend):**
```rust
use tauri::{AppHandle, Emitter};

fn emit_event(app: &AppHandle) {
    app.emit("backend-event", "payload data").unwrap();
}
```

**Frontend (listen):**
```typescript
import { listen } from '@tauri-apps/api/event';

const unlisten = await listen('backend-event', (event) => {
  console.log('Received:', event.payload);
});

// Call unlisten() when done
```

**Frontend (emit to backend):**
```typescript
import { emit } from '@tauri-apps/api/event';

await emit('frontend-event', { data: 'value' });
```

### Commands

- **Direction**: Frontend -> Rust backend
- **Protocol**: JSON-RPC-based abstraction
- **API**: Similar to browser's `fetch()` API
- **Requirement**: Arguments and return data must be JSON-serializable

**Rust command definition:**
```rust
#[tauri::command]
fn greet(name: &str) -> String {
    format!("Hello, {}!", name)
}

fn main() {
    tauri::Builder::default()
        .invoke_handler(tauri::generate_handler![greet])
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}
```

**Frontend invocation:**
```typescript
import { invoke } from '@tauri-apps/api/core';

const greeting = await invoke('greet', { name: 'World' });
console.log(greeting); // "Hello, World!"
```

**Async command with Result:**
```rust
#[tauri::command]
async fn read_file(path: String) -> Result<String, String> {
    std::fs::read_to_string(&path)
        .map_err(|e| e.to_string())
}
```

## IPC Patterns

Tauri provides two IPC security patterns: **Brownfield** (default) and **Isolation**.

---

## Brownfield Pattern

### What It Is

The brownfield pattern is Tauri's **default** IPC approach. It prioritizes compatibility with existing web frontend projects by requiring minimal modifications.

### When to Use

- Migrating existing web applications to desktop
- Rapid prototyping and development
- Applications with trusted frontend code
- Simple applications with limited IPC surface

### Why Use It

- Zero configuration required
- Minimal changes to existing web code
- Direct access to Tauri APIs
- Fastest development path

### Configuration

Brownfield is the default. Explicit configuration is optional:

```json
{
  "app": {
    "security": {
      "pattern": {
        "use": "brownfield"
      }
    }
  }
}
```

**Note:** There are no additional configuration options for brownfield.

### Code Example

**Rust backend:**
```rust
#[tauri::command]
fn process_data(input: String) -> Result<String, String> {
    // Direct processing without isolation layer
    Ok(format!("Processed: {}", input))
}
```

**Frontend:**
```typescript
import { invoke } from '@tauri-apps/api/core';

// Direct invocation - no isolation layer
const result = await invoke('process_data', { input: 'test' });
```

### Security Considerations

- Frontend code has direct access to all exposed commands
- No additional validation layer between frontend and backend
- Supply chain attacks in frontend dependencies could invoke commands
- Rely on command-level validation in Rust

---

## Isolation Pattern

### What It Is

The isolation pattern intercepts and modifies **all** Tauri API messages from the frontend using JavaScript before they reach Tauri Core. A secure JavaScript application (the Isolation application) runs in a sandboxed iframe to validate and encrypt all IPC communications.

### When to Use

- Applications with many frontend dependencies
- High-security requirements
- Handling sensitive data or operations
- Public-facing applications
- When supply chain attacks are a concern

### Why Use It

**Protection against Development Threats:**
- Validates all IPC calls before execution
- Catches malicious or unwanted frontend calls
- Mitigates supply chain attack risks
- Provides a checkpoint for all communications

**Tauri recommends using isolation whenever feasible.**

### How It Works

1. Tauri's IPC handler receives a message from frontend
2. Message routes to the Isolation application (sandboxed iframe)
3. Isolation hook validates and potentially modifies the message
4. Message encrypts using AES-GCM with runtime-generated keys
5. Encrypted message returns to IPC handler
6. Encrypted message passes to Tauri Core for decryption and execution

**Key Security Features:**
- New encryption keys generated on each application launch
- Sandboxed iframe prevents isolation code manipulation
- All IPC calls validated, including event-based APIs

### Configuration

**tauri.conf.json:**
```json
{
  "app": {
    "security": {
      "pattern": {
        "use": "isolation",
        "options": {
          "dir": "../dist-isolation"
        }
      }
    }
  }
}
```

### Code Example

**Directory structure:**
```
project/
  src/           # Main frontend
  src-tauri/     # Rust backend
  dist-isolation/
    index.html
    index.js
```

**dist-isolation/index.html:**
```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Isolation Secure Script</title>
  </head>
  <body>
    <script src="index.js"></script>
  </body>
</html>
```

**dist-isolation/index.js:**
```javascript
window.__TAURI_ISOLATION_HOOK__ = (payload) => {
  // Log all IPC calls for debugging
  console.log('IPC call intercepted:', payload);

  // Return payload unchanged (passthrough)
  return payload;
};
```

**Validation example (index.js):**
```javascript
window.__TAURI_ISOLATION_HOOK__ = (payload) => {
  // Validate command calls
  if (payload.cmd === 'invoke') {
    const { __tauriModule, message } = payload;

    // Block unauthorized file system access
    if (message.cmd === 'readFile') {
      const path = message.path;
      if (!path.startsWith('/allowed/directory/')) {
        console.error('Blocked unauthorized file access:', path);
        return null; // Block the request
      }
    }

    // Validate specific commands
    if (message.cmd === 'deleteItem') {
      if (!confirm('Are you sure you want to delete this item?')) {
        return null; // User cancelled
      }
    }
  }

  return payload;
};
```

**Comprehensive validation example:**
```javascript
const ALLOWED_COMMANDS = ['greet', 'read_config', 'save_settings'];
const BLOCKED_PATHS = ['/etc/', '/usr/', '/System/'];

window.__TAURI_ISOLATION_HOOK__ = (payload) => {
  // Validate invoke commands
  if (payload.cmd === 'invoke') {
    const commandName = payload.message?.cmd;

    // Whitelist approach
    if (!ALLOWED_COMMANDS.includes(commandName)) {
      console.warn('Blocked unknown command:', commandName);
      return null;
    }

    // Validate path arguments
    const args = payload.message?.args || {};
    if (args.path) {
      for (const blocked of BLOCKED_PATHS) {
        if (args.path.startsWith(blocked)) {
          console.error('Blocked access to protected path:', args.path);
          return null;
        }
      }
    }
  }

  // Validate event emissions
  if (payload.cmd === 'emit') {
    const eventName = payload.event;
    // Add event validation as needed
  }

  return payload;
};
```

### Performance Considerations

- AES-GCM encryption overhead is minimal for most applications
- Comparable to TLS encrypti
Files: 1
Size: 10.7 KB
Complexity: 14/100
Category: Web Dev

Related in Web Dev