.claude/skills/tauri-plugin-permissions/SKILL.md
Guides users through configuring Tauri plugin permissions, capabilities, and security. Covers platform-specific capabilities, window-targeted permissions, using official and community plugin permissions, and writing custom plugin permissions with scopes.
npx skillsauth add rdjakovic/todo2 managing-tauri-plugin-permissionsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Tauri's capability and permission system provides granular security control for desktop and mobile applications. This skill covers configuring capabilities for windows and platforms, using plugin permissions effectively, and writing custom plugin permissions.
Capabilities are JSON configuration files that assign permissions to specific windows and platforms. They follow the principle of least privilege.
Location: src-tauri/capabilities/
Structure:
{
"identifier": "capability-name",
"description": "Human-readable purpose",
"local": true,
"windows": ["window-label"],
"permissions": ["plugin:allow-action"],
"platforms": ["linux", "windows", "macos", "android", "ios"]
}
Permissions operate at two levels:
allow-write-text-file)Restrict capabilities to specific operating systems using the platforms field:
{
"identifier": "desktop-fs-access",
"description": "Filesystem access for desktop platforms",
"windows": ["main"],
"permissions": ["fs:allow-home-read"],
"platforms": ["linux", "windows", "macos"]
}
Available platforms: linux, windows, macos, android, ios
{
"identifier": "mobile-camera",
"description": "Camera access for mobile devices",
"windows": ["main"],
"permissions": ["camera:allow-capture"],
"platforms": ["android", "ios"]
}
Define windows in tauri.conf.json:
{
"windows": [
{
"label": "main",
"title": "Main Window",
"width": 800,
"height": 600
},
{
"label": "settings",
"title": "Settings",
"width": 400,
"height": 300
}
]
}
Create separate capability files for each window's needs:
src-tauri/capabilities/main-window.json:
{
"identifier": "main-window-capabilities",
"description": "Full access for main window",
"local": true,
"windows": ["main"],
"permissions": [
"fs:allow-home-read",
"fs:allow-home-write",
"dialog:allow-open",
"dialog:allow-save"
]
}
src-tauri/capabilities/settings-window.json:
{
"identifier": "settings-window-capabilities",
"description": "Limited access for settings window",
"local": true,
"windows": ["settings"],
"permissions": [
"fs:allow-app-read",
"fs:allow-app-write"
]
}
{
"identifier": "shared-dialog",
"description": "Dialog access for multiple windows",
"local": true,
"windows": ["main", "settings"],
"permissions": ["dialog:allow-ask", "dialog:allow-message"]
}
Every plugin provides a default permission set with baseline access. Enable it with:
{
"permissions": ["plugin-name:default"]
}
permissions/autogenerated directoriesplugin-name:permission-name
Examples:
fs:allow-readfs:allow-write-text-filedialog:allow-openshell:allow-spawnRestrict permissions to specific paths:
{
"identifier": "default",
"description": "Main window capabilities",
"windows": ["main"],
"permissions": [
"fs:allow-write-text-file",
{
"identifier": "fs:allow-read",
"allow": [{ "path": "$HOME/Documents/**" }]
},
{
"identifier": "fs:allow-write",
"allow": [{ "path": "$APP/**" }]
}
]
}
| Variable | Description |
|----------|-------------|
| $APP | Application data directory |
| $HOME | User home directory |
| $RESOURCE | Application resources |
| $TEMP | Temporary directory |
| $DESKTOP | User desktop |
| $DOCUMENT | User documents |
| $DOWNLOAD | User downloads |
Explicitly deny specific operations:
{
"permissions": [
"fs:default",
"fs:deny-write-text-file"
]
}
Create a plugin with the Tauri CLI:
cargo tauri plugin new my-plugin
cd tauri-plugin-my-plugin
src/commands.rs:
use tauri::{command, AppHandle, Runtime};
#[command]
pub(crate) async fn read_data<R: Runtime>(
key: String,
app: AppHandle<R>,
) -> Result<String, String> {
// Implementation
Ok(format!("Data for key: {}", key))
}
#[command]
pub(crate) async fn write_data<R: Runtime>(
key: String,
value: String,
app: AppHandle<R>,
) -> Result<(), String> {
// Implementation
Ok(())
}
#[command]
pub(crate) async fn delete_data<R: Runtime>(
key: String,
app: AppHandle<R>,
) -> Result<(), String> {
// Implementation
Ok(())
}
src/build.rs:
const COMMANDS: &[&str] = &["read_data", "write_data", "delete_data"];
fn main() {
tauri_plugin::Builder::new(COMMANDS)
.global_api_script_path("./api-iife.js")
.build();
}
This generates:
allow-read-data / deny-read-dataallow-write-data / deny-write-dataallow-delete-data / deny-delete-datapermissions/default.toml:
"$schema" = "schemas/schema.json"
[default]
description = "Default permissions for my-plugin. Allows read operations only."
permissions = ["allow-read-data"]
permissions/read-write.toml:
"$schema" = "schemas/schema.json"
[[set]]
identifier = "read-write"
description = "Allows both read and write operations"
permissions = ["allow-read-data", "allow-write-data"]
permissions/full-access.toml:
"$schema" = "schemas/schema.json"
[[set]]
identifier = "full-access"
description = "Allows all operations including delete"
permissions = ["allow-read-data", "allow-write-data", "allow-delete-data"]
src/lib.rs:
use tauri::{
plugin::{Builder, TauriPlugin},
Manager, Runtime,
};
mod commands;
pub fn init<R: Runtime>() -> TauriPlugin<R> {
Builder::new("my-plugin")
.invoke_handler(tauri::generate_handler![
commands::read_data,
commands::write_data,
commands::delete_data,
])
.build()
}
guest-js/index.ts:
import { invoke } from '@tauri-apps/api/core';
export async function readData(key: string): Promise<string> {
return await invoke('plugin:my-plugin|read_data', { key });
}
export async function writeData(key: string, value: string): Promise<void> {
return await invoke('plugin:my-plugin|write_data', { key, value });
}
export async function deleteData(key: string): Promise<void> {
return await invoke('plugin:my-plugin|delete_data', { key });
}
In your application's capability file:
{
"identifier": "default",
"windows": ["main"],
"permissions": [
"my-plugin:default",
"my-plugin:read-write",
"my-plugin:allow-delete-data"
]
}
src-tauri/capabilities/desktop.json:
{
"$schema": "../gen/schemas/desktop-schema.json",
"identifier": "desktop",
"windows": ["main"],
"platforms": ["linux", "windows", "macos"],
"permissions": [
"core:default",
"fs:default",
{ "identifier": "fs:allow-read", "allow": [{ "path": "$HOME/Documents/**" }] },
{ "identifier": "fs:allow-write", "allow": [{ "path": "$APP/**" }] },
"dialog:allow-open",
"dialog:allow-save",
"shell:allow-open"
]
}
src-tauri/capabilities/mobile.json:
{
"identifier": "mobile",
"windows": ["main"],
"platforms": ["android", "ios"],
"permissions": [
"fs:allow-app-read",
"fs:allow-app-write",
"notification:default"
]
}
If you encounter permission errors:
src-tauri/capabilities/windows array contains the correct window labelsplatforms includes your target OSdevelopment
Enforce web security and avoid security vulnerabilities
development
Guides users through distributing Tauri applications on Windows, including creating MSI and NSIS installers, customizing installer behavior, configuring WebView2 installation modes, and submitting apps to the Microsoft Store.
documentation
Guides users through Tauri window customization including custom titlebar implementation, transparent windows, window decorations, drag regions, window menus, submenus, and menu keyboard shortcuts for desktop applications.
tools
Assists users with updating Tauri dependencies including the Tauri CLI, Rust crates, JavaScript packages, and checking for outdated versions to upgrade to the latest version.