---
name: configuring-tauri-permissions
description: "Configure the Tauri v2 permission system controlling frontend access to backend commands and resources. USE WHEN defining allow/deny lists, enabling plugin permissions, referencing permission identifiers, or wiring permissions into scopes and capabilities."
cluster: tauri
version: 1.0.0
---

# Tauri Permissions Configuration

This skill covers the Tauri v2 permission system for controlling frontend access to backend commands and system resources.

## Permission System Overview

Permissions in Tauri are explicit privileges that grant or deny access to specific commands. They form the security boundary between frontend code and system resources.

### Core Components

| Component | Purpose |
|-----------|---------|
| Permission | Defines access to specific commands |
| Scope | Restricts commands to specific paths/resources |
| Capability | Links permissions to windows/webviews |
| Identifier | Unique name referencing a permission |

### Security Model

- Frontend code cannot access commands without explicit permission
- Deny rules always take precedence over allow rules
- Permissions must be linked to capabilities to be active
- Each window/webview can have different permissions

## Permission Identifiers

### Naming Convention

Format: `<plugin-name>:<permission-type>`

| Pattern | Example | Description |
|---------|---------|-------------|
| `<name>:default` | `fs:default` | Default permission set |
| `<name>:allow-<command>` | `fs:allow-read-file` | Allow specific command |
| `<name>:deny-<command>` | `fs:deny-write-file` | Deny specific command |
| `<name>:allow-<scope>` | `fs:allow-app-read` | Allow with predefined scope |

### Identifier Rules

- Lowercase ASCII letters only: `[a-z]`
- Maximum length: 116 characters
- Plugin prefixes (`tauri-plugin-`) added automatically at compile time

## Directory Structure

### Application Structure

```
src-tauri/
├── capabilities/
│   ├── default.json          # Main capability file
│   └── admin.toml            # Additional capabilities
├── permissions/
│   └── custom-permission.toml # Custom app permissions
└── tauri.conf.json
```

### Plugin Structure

```
tauri-plugin-example/
├── permissions/
│   ├── default.toml          # Default permission set
│   ├── autogenerated/        # Auto-generated from commands
│   │   └── commands/
│   └── custom-scope.toml     # Custom scopes
└── src/
    ├── commands.rs
    └── build.rs
```

## Capability Configuration

Capabilities link permissions to windows and define what frontend contexts can access.

### JSON Format (Recommended for Apps)

```json
{
  "$schema": "../gen/schemas/desktop-schema.json",
  "identifier": "main-capability",
  "description": "Main window permissions",
  "windows": ["main"],
  "permissions": [
    "core:default",
    "fs:default",
    "fs:allow-read-text-file",
    {
      "identifier": "fs:allow-write-text-file",
      "allow": [{ "path": "$APPDATA/*" }]
    }
  ]
}
```

### TOML Format

```toml
"$schema" = "../gen/schemas/desktop-schema.json"
identifier = "main-capability"
description = "Main window permissions"
windows = ["main"]
permissions = [
  "core:default",
  "fs:default",
  "fs:allow-read-text-file"
]

[[permissions]]
identifier = "fs:allow-write-text-file"
allow = [{ path = "$APPDATA/*" }]
```

### Window Targeting

```json
{
  "identifier": "admin-capability",
  "windows": ["admin", "settings"],
  "permissions": ["fs:allow-write-all"]
}
```

Use `"*"` to target all windows:

```json
{
  "windows": ["*"],
  "permissions": ["core:default"]
}
```

### Platform-Specific Capabilities

```json
{
  "identifier": "desktop-capability",
  "platforms": ["linux", "macOS", "windows"],
  "windows": ["main"],
  "permissions": ["fs:allow-app-read-recursive"]
}
```

```json
{
  "identifier": "mobile-capability",
  "platforms": ["iOS", "android"],
  "windows": ["main"],
  "permissions": ["fs:allow-app-read"]
}
```

## Allow and Deny Lists

### Basic Scope Configuration

```json
{
  "identifier": "fs:allow-read-file",
  "allow": [
    { "path": "$HOME/Documents/*" },
    { "path": "$APPDATA/**" }
  ],
  "deny": [
    { "path": "$HOME/Documents/secrets/*" }
  ]
}
```

### Scope Variables

| Variable | Description |
|----------|-------------|
| `$APP` | Application install directory |
| `$APPCONFIG` | App config directory |
| `$APPDATA` | App data directory |
| `$APPLOCALDATA` | App local data directory |
| `$APPCACHE` | App cache directory |
| `$APPLOG` | App log directory |
| `$HOME` | User home directory |
| `$DESKTOP` | Desktop directory |
| `$DOCUMENT` | Documents directory |
| `$DOWNLOAD` | Downloads directory |
| `$RESOURCE` | App resource directory |
| `$TEMP` | Temporary directory |

### Glob Patterns

| Pattern | Matches |
|---------|---------|
| `*` | Any file in directory |
| `**` | Recursive (all subdirectories) |
| `*.txt` | Files with .txt extension |

### Deny Precedence

Deny rules always override allow rules:

```json
{
  "permissions": [
    {
      "identifier": "fs:allow-read-file",
      "allow": [{ "path": "$HOME/**" }],
      "deny": [{ "path": "$HOME/.ssh/**" }]
    }
  ]
}
```

## Plugin Permissions

### Using Default Plugin Permissions

```json
{
  "permissions": [
    "fs:default",
    "shell:default",
    "http:default",
    "dialog:default"
  ]
}
```

### Common Plugin Permission Patterns

#### Filesystem Plugin

```json
{
  "permissions": [
    "fs:default",
    "fs:allow-read-text-file",
    "fs:allow-write-text-file",
    "fs:allow-app-read-recursive",
    "fs:allow-app-write-recursive",
    "fs:deny-default"
  ]
}
```

#### HTTP Plugin

```json
{
  "permissions": [
    "http:default",
    {
      "identifier": "http:default",
      "allow": [{ "url": "https://api.example.com/*" }],
      "deny": [{ "url": "https://api.example.com/admin/*" }]
    }
  ]
}
```

#### Shell Plugin

```json
{
  "permissions": [
    "shell:allow-open",
    {
      "identifier": "shell:allow-execute",
      "allow": [
        { "name": "git", "cmd": "git", "args": true }
      ]
    }
  ]
}
```

### Directory-Specific Filesystem Permissions

| Permission | Access |
|------------|--------|
| `fs:allow-appdata-read` | Read $APPDATA (non-recursive) |
| `fs:allow-appdata-read-recursive` | Read $APPDATA (recursive) |
| `fs:allow-appdata-write` | Write $APPDATA (non-recursive) |
| `fs:allow-appdata-write-recursive` | Write $APPDATA (recursive) |
| `fs:allow-home-read-recursive` | Read $HOME (recursive) |
| `fs:allow-temp-write` | Write to temp directory |

## Custom Permission Definition

### TOML Permission File

Create `src-tauri/permissions/my-permission.toml`:

```toml
[[permission]]
identifier = "my-app:config-access"
description = "Access to app configuration files"
commands.allow = ["read_config", "write_config"]

[[scope.allow]]
path = "$APPCONFIG/*"

[[scope.deny]]
path = "$APPCONFIG/secrets.json"
```

### Permission Sets

Group multiple permissions:

```toml
[[set]]
identifier = "my-app:full-access"
description = "Full application access"
permissions = [
  "my-app:config-access",
  "fs:allow-app-read-recursive",
  "fs:allow-app-write-recursive"
]
```

### Auto-Generated Command Permissions

In plugin `src/build.rs`:

```rust
const COMMANDS: &[&str] = &["get_user", "save_user", "delete_user"];

fn main() {
    tauri_plugin::Builder::new(COMMANDS)
        .build();
}
```

This generates:
- `allow-get-user` / `deny-get-user`
- `allow-save-user` / `deny-save-user`
- `allow-delete-user` / `deny-delete-user`

### Default Permission Set

Create `permissions/default.toml`:

```toml
[default]
description = "Default permissions for my-plugin"
permissions = [
  "allow-get-user",
  "allow-save-user"
]
```

## Remote Access Configuration

Allow remote URLs to access Tauri APIs (use with caution):

```json
{
  "identifier": "remote-capability",
  "windows": ["main"],
  "remote": {
    "urls": ["https://*.myapp.com"]
  },
  "permissions": [
    "core:default"
  ]
}
```

**Security Warning**: Linux and Android cannot distinguish iframe requests from window requests.

## Configuration in tauri.conf.json

Reference capabilities by identifier:

```json
{
  "app": {
    "security": {
      "capabilities": ["main-capability", "admin-capability"]
    }
  }
}
```

Or inline capabilities directly:

```json
{
  "app": {
    "security": {
      "capabilities": [
        {
          "identifier": "inline-capability",
          "windows": ["*"],
          "permissions": ["core:default"]
        }
      ]
    }
  }
}
```

## Troubleshooting

### Common Errors

**"Not allowed on this command"**
- Verify command permission is in capability
- Check scope includes the target path
- Ensure capability targets correct window

**Permission not found**
- Check identifier spelling (lowercase only)
- Verify plugin is installed
- Run `cargo build` to regenerate permissions

### Debugging Permissions

1. Check generated schema: `src-tauri/gen/schemas/`
2. Review capability files load correctly
3. Verify window names match capability targets
4. Check deny rules are not blocking access

## Best Practices

1. **Principle of Least Privilege**: Only grant permissions actually needed
2. **Use Specific Scopes**: Prefer `$APPDATA/*` over `$HOME/**`
3. **Deny Sensitive Paths**: Always deny access to `.ssh`, credentials, etc.
4. **Separate Capabilities**: Use different capabilities for different window types
5. **Document Custom Permissions**: Include clear descriptions
6. **Review Plugin Defaults**: Understand what default permissions grant
7. **Platform-Specific Config**: Use platform targeting for OS-specific needs
