Skip to content

Instantly share code, notes, and snippets.

@LinuxSBC
Last active March 13, 2026 01:07
Show Gist options
  • Select an option

  • Save LinuxSBC/7c39374130d2d443871ddde64cba18a3 to your computer and use it in GitHub Desktop.

Select an option

Save LinuxSBC/7c39374130d2d443871ddde64cba18a3 to your computer and use it in GitHub Desktop.

Revisions

  1. LinuxSBC revised this gist Mar 21, 2025. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion README.md
    Original file line number Diff line number Diff line change
    @@ -85,7 +85,7 @@ Then, on browsers like Floorp and Zen, which require the files be put in `~/.moz
    <details>
    <summary>Curious about why it's a security risk?</summary>

    1Password only lets certain apps integrate with it, as described below. If this were to run directly through Bash, that would mean that we'd need to allow 1Password to integrate with everything run by Bash, which is a lot. Basically everything running on your system would then have access. To get around this, we run `exec /opt/1Password/1Password-BrowserSupport "$@"` instead of just `/opt/1Password/1Password-BrowserSupport "$@"`. The `exec` command basically replaces the Bash shell with whatever command you ran, which means that `1Password-BrowserSupport`'s parent process is now your browser, not Bash.
    1Password only lets certain apps integrate with it, as described below. If this were to run directly through Bash, that would mean that we'd need to allow 1Password to integrate with everything run by Bash, which is a lot. Basically everything running on your system would then have access to your 1Password vault. To get around this, we run `exec /opt/1Password/1Password-BrowserSupport "$@"` instead of just `/opt/1Password/1Password-BrowserSupport "$@"`. The `exec` command basically replaces the Bash shell with whatever command you ran, which means that `1Password-BrowserSupport`'s parent process is now your browser, not Bash.

    </details>

  2. LinuxSBC revised this gist Mar 21, 2025. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion README.md
    Original file line number Diff line number Diff line change
    @@ -3,7 +3,7 @@ This script will automatically add support for 1Password to integrate with Flatp
    Note: The 1Password app itself needs to be installed as a native package.

    To use this script, follow these steps:
    1. Download the script.
    1. Download the script (right-click on "Raw" and click "Save Link As").
    2. Open your terminal in the directory that you downloaded the script to. For example, if it's in your Downloads folder, run `cd Downloads` after opening your terminal.
    3. Mark the script as executable using the command `chmod +x 1password-flatpak-browser-integration.sh`.
    4. Run the script using the command `./1password-flatpak-browser-integration.sh`.
  3. LinuxSBC revised this gist Mar 21, 2025. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion README.md
    Original file line number Diff line number Diff line change
    @@ -85,7 +85,7 @@ Then, on browsers like Floorp and Zen, which require the files be put in `~/.moz
    <details>
    <summary>Curious about why it's a security risk?</summary>

    1Password only lets certain apps integrate with it, as described below. If this were to run directly through Bash, that would mean that we'd need to allow 1Password to integrate with everything run by Bash, which is a lot. Basically everything running on your system would then have access. To get around this, we run `exec /opt/1Password/1Password-BrowserSupport "$@"` instead of just `/opt/1Password/1Password-BrowserSupport "$@"`. The `exec` command basically replaces the Bash shell with whatever command you ran, which means that `1Password-BrowserSupport`'s parent process is now your browser, not Bash.
    1Password only lets certain apps integrate with it, as described below. If this were to run directly through Bash, that would mean that we'd need to allow 1Password to integrate with everything run by Bash, which is a lot. Basically everything running on your system would then have access. To get around this, we run `exec /opt/1Password/1Password-BrowserSupport "$@"` instead of just `/opt/1Password/1Password-BrowserSupport "$@"`. The `exec` command basically replaces the Bash shell with whatever command you ran, which means that `1Password-BrowserSupport`'s parent process is now your browser, not Bash.

    </details>

  4. LinuxSBC revised this gist Mar 21, 2025. 2 changed files with 25 additions and 8 deletions.
    18 changes: 11 additions & 7 deletions 1password-flatpak-browser-integration.sh
    Original file line number Diff line number Diff line change
    @@ -1,17 +1,18 @@
    #!/bin/bash
    set -oue pipefail

    echo "This script will help you set up 1Password in a Flatpak browser."
    echo

    PACKAGE_LIST=$(flatpak list --app --columns=application)

    INFO='\033[0;36m' # Cyan for general information
    SUCCESS='\033[0;32m' # Green for success messages
    WARN='\033[0;33m' # Yellow for warnings
    ERROR='\033[0;31m' # Red for errors
    NC='\033[0m' # No Color

    echo "This script will help you set up 1Password in a Flatpak browser."
    echo -e "${WARN}Note: It will make it possible for any Flatpak application to integrate, not just some. Consider if you find this worth the risk.${NC}"
    echo

    PACKAGE_LIST=$(flatpak list --app --columns=application)

    ALLOWED_EXTENSIONS_FIREFOX='"allowed_extensions": [
    "{0a75d802-9aed-41e7-8daa-24c067386e82}",
    "{25fc87fa-4d31-4fee-b5c1-c32a7844c063}",
    @@ -99,7 +100,7 @@ cat <<EOF > "$HOME/.var/app/$FLATPAK_ID/data/bin/1password-wrapper.sh"
    if [ "\${container-}" = flatpak ]; then
    flatpak-spawn --host /opt/1Password/1Password-BrowserSupport "\$@"
    else
    /opt/1Password/1Password-BrowserSupport "\$@"
    exec /opt/1Password/1Password-BrowserSupport "\$@"
    fi
    EOF
    chmod +x "$HOME/.var/app/$FLATPAK_ID/data/bin/1password-wrapper.sh"
    @@ -156,6 +157,7 @@ add_native_messaging_host() {
    EOF
    }

    PUT_FILES_IN_MOZILLA_DIR=false
    WRAPPER_PATH="$HOME/.var/app/$FLATPAK_ID/data/bin/1password-wrapper.sh"
    if [[ "$BROWSER_TYPE" = "chromium" ]]; then
    add_native_messaging_host "$WRAPPER_PATH" "$ALLOWED_EXTENSIONS_CHROMIUM" "$NATIVE_MESSAGING_HOSTS_DIR"
    @@ -171,11 +173,13 @@ elif [[ "$BROWSER_TYPE" = "firefox" ]]; then
    if [[ "$CONTINUE" = "N" ]] || [[ "$CONTINUE" = "n" ]]; then
    echo -e "${INFO}Skipping${NC}"
    else
    PUT_FILES_IN_MOZILLA_DIR=true
    cp "$HOME/.var/app/$FLATPAK_ID/data/bin/1password-wrapper.sh" "$HOME/.mozilla/native-messaging-hosts/1password-wrapper.sh"
    flatpak override --user --filesystem="$HOME/.mozilla/native-messaging-hosts" "$FLATPAK_ID"

    WRAPPER_PATH="$HOME/.mozilla/native-messaging-hosts/1password-wrapper.sh" # For browsers that need the file in ~/.mozilla, like Zen and Floorp
    NATIVE_MESSAGING_HOSTS_DIR="$HOME/.mozilla/native-messaging-hosts"
    sudo chattr -i "$NATIVE_MESSAGING_HOSTS_DIR/com.1password.1password.json" # Remove read-only flag if it exists
    add_native_messaging_host "$WRAPPER_PATH" "$ALLOWED_EXTENSIONS_FIREFOX" "$NATIVE_MESSAGING_HOSTS_DIR"

    echo -e "${INFO}Marking $HOME/.mozilla/native-messaging-hosts/com.1password.1password.json as read-only using chattr +i. To undo, run this command:${NC}"
    @@ -199,7 +203,7 @@ if grep -q 'flatpak-session-helper' /etc/1password/custom_allowed_browsers; then
    echo -e "${WARN}Already added to allowed browsers${NC}"
    else
    echo -e "${INFO}Adding to allowed browsers${NC}"
    echo 'flatpak-session-helper' | sudo tee -a /etc/1password/custom_allowed_browsers >/dev/null
    echo -e 'flatpak-session-helper' | sudo tee -a /etc/1password/custom_allowed_browsers >/dev/null
    fi


    15 changes: 14 additions & 1 deletion README.md
    Original file line number Diff line number Diff line change
    @@ -78,4 +78,17 @@ Firefox forks have several different places where the native-messaging-hosts dir

    The first two places are somewhat annoying to find but not too difficult, but the third causes problems. Since it's on the host, the Flatpak doesn't naturally have access to it, so we need to give it permission to access the `~/.mozilla/native-messaging-hosts` directory. Then, since this would also be used by native installations of browsers like Firefox, the script needs to be reconfigured to detect if it's being run from a Flatpak container and choose whether or not to run `flatpak-spawn --host` accordingly. Finally, the JSON file would usually be overwritten by 1Password every time it starts, so we need to mark it as read-only using `chattr +i`.

    Another difficulty is finding the directory where the native messaging host JSON should go. Chromium-based browsers put it in `~/.var/app/<browser ID>/config/<browser name>/NativeMessagingHosts` or `~/.var/app/<browser ID>/config/<company name>/<browser name>/NativeMessagingHosts`. Luckily, the NativeMessagingHosts directory is already created, so we just have to run a `find` command to locate it. Firefox-based browsers don't create their `native-messaging-hosts` folder automatically, so we need to locate the `profiles.ini` file and derive the location from there.
    Another difficulty is finding the directory where the native messaging host JSON should go. Chromium-based browsers put it in `~/.var/app/<browser ID>/config/<browser name>/NativeMessagingHosts` or `~/.var/app/<browser ID>/config/<company name>/<browser name>/NativeMessagingHosts`. Luckily, the NativeMessagingHosts directory is already created, so we just have to run a `find` command to locate it. Firefox-based browsers don't create their `native-messaging-hosts` folder automatically, so we need to locate the `profiles.ini` file and derive the location from there.

    Then, on browsers like Floorp and Zen, which require the files be put in `~/.mozilla`, this custom JSON file would interere with the native version of Firefox (or Floorp or Zen) because the browser would be attempting to run `flatpak-spawn --host` without being in a Flatpak, which fails. To get around this, we need a slightly more complex script that runs `flatpak-spawn --host` if it's being run from a Flatpak and just runs the command normally otherwise. However, that normal command is being run by `bash`, not by the browser, which is a security risk, so I'm running it through `exec` instead.

    <details>
    <summary>Curious about why it's a security risk?</summary>

    1Password only lets certain apps integrate with it, as described below. If this were to run directly through Bash, that would mean that we'd need to allow 1Password to integrate with everything run by Bash, which is a lot. Basically everything running on your system would then have access. To get around this, we run `exec /opt/1Password/1Password-BrowserSupport "$@"` instead of just `/opt/1Password/1Password-BrowserSupport "$@"`. The `exec` command basically replaces the Bash shell with whatever command you ran, which means that `1Password-BrowserSupport`'s parent process is now your browser, not Bash.

    </details>

    # Telling 1Password that it can connect

    On Linux, 1Password will only accept integration requests from processes in its internal list or in `/etc/1password/custom_allowed_browsers`. Flatpak browsers are not in the internal list, so we need to manually add them to `custom_allowed_browsers`. Luckily, every command run from a Flatpak is actually run by `flatpak-session-helper`, so just adding that to the list allows every Flatpak to integrate with 1Password. This does make it easier for a malicious Flatpak to integrate with it, however, so be mindful of that.
  5. LinuxSBC created this gist Mar 20, 2025.
    213 changes: 213 additions & 0 deletions 1password-flatpak-browser-integration.sh
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,213 @@
    #!/bin/bash
    set -oue pipefail

    echo "This script will help you set up 1Password in a Flatpak browser."
    echo

    PACKAGE_LIST=$(flatpak list --app --columns=application)

    INFO='\033[0;36m' # Cyan for general information
    SUCCESS='\033[0;32m' # Green for success messages
    WARN='\033[0;33m' # Yellow for warnings
    ERROR='\033[0;31m' # Red for errors
    NC='\033[0m' # No Color

    ALLOWED_EXTENSIONS_FIREFOX='"allowed_extensions": [
    "{0a75d802-9aed-41e7-8daa-24c067386e82}",
    "{25fc87fa-4d31-4fee-b5c1-c32a7844c063}",
    "{d634138d-c276-4fc8-924b-40a0ea21d284}"
    ]'
    ALLOWED_EXTENSIONS_CHROMIUM='"allowed_origins": [
    "chrome-extension://hjlinigoblmkhjejkmbegnoaljkphmgo/",
    "chrome-extension://gejiddohjgogedgjnonbofjigllpkmbf/",
    "chrome-extension://khgocmkkpikpnmmkgmdnfckapcdkgfaf/",
    "chrome-extension://aeblfdkhhhdcdjpifhhbdiojplfjncoa/",
    "chrome-extension://dppgmdbiimibapkepcbdbmkaabgiofem/"
    ]'

    is_firefox_dir() {
    local dir="$1"

    # Skip if not a directory or if it's . or .. or .cache
    if [[ ! -d "$dir" ]] || [[ "$(basename "$dir")" = "." ]] || [[ "$(basename "$dir")" = ".." ]] || [[ "$(basename "$dir")" = "cache" ]] || [[ "$(basename "$dir")" = ".cache" ]]; then
    return 1
    elif [[ -f "$dir/profiles.ini" ]]; then
    return 0
    else
    return 1
    fi
    }

    list_flatpak_browsers() {
    BROWSER_ID_LIST=("$@")

    for BROWSER_ID in "${BROWSER_ID_LIST[@]}"; do
    if echo "$PACKAGE_LIST" | grep -q "$BROWSER_ID"; then
    MATCHING_BROWSERS=$(echo "$PACKAGE_LIST" | grep "$BROWSER_ID")
    while IFS= read -r BROWSER || [[ -n $BROWSER ]]; do
    echo -e "${INFO} - $BROWSER${NC}"
    done < <(printf '%s' "$MATCHING_BROWSERS") # https://superuser.com/questions/284187/how-to-iterate-over-lines-in-a-variable-in-bash
    fi
    done
    }


    # Getting what browser to install for
    echo -e "${INFO}Detected Chromium-based browsers (incomplete list):${NC}"
    CHROMIUM_BROWSER_ID_LIST=("com.google.Chrome" "com.brave.Browser" "com.vivaldi.Vivaldi" "com.opera.Opera" "com.microsoft.Edge" "ru.yandex.Browser" "org.chromium.Chromium" "io.github.ungoogled_software.ungoogled_chromium")
    list_flatpak_browsers "${CHROMIUM_BROWSER_ID_LIST[@]}"

    echo -e "${INFO}Detected Firefox-based browsers (incomplete list):${NC}"
    FIREFOX_BROWSER_ID_LIST=("org.mozilla.firefox" "one.ablaze.floorp" "io.gitlab.librewolf-community" "org.torproject.torbrowser-launcher" "app.zen_browser.zen" "org.garudalinux.firedragon" "net.mullvad.MullvadBrowser" "net.waterfox.waterfox")
    list_flatpak_browsers "${FIREFOX_BROWSER_ID_LIST[@]}"

    echo

    echo -n "Enter the name of your browser's Flatpak application ID (e.g. com.google.Chrome): "
    read -r FLATPAK_ID
    if ! echo "$PACKAGE_LIST" | grep -q "$FLATPAK_ID"; then
    echo -e "${ERROR}ERROR: Could not find the specified browser${NC}"
    exit 1
    fi
    if [[ " ${FIREFOX_BROWSER_ID_LIST[*]} " =~ [[:space:]]${FLATPAK_ID}[[:space:]] ]]; then
    BROWSER_TYPE="firefox"
    elif [[ " ${CHROMIUM_BROWSER_ID_LIST[*]} " =~ [[:space:]]${FLATPAK_ID}[[:space:]] ]]; then
    BROWSER_TYPE="chromium"
    else
    echo "Could not determine browser type. Is your browser based on Chromium or Firefox?"
    echo -n "Enter 'chromium' or 'firefox': "
    read -r BROWSER_TYPE
    fi
    if [[ "$BROWSER_TYPE" != "chromium" ]] && [[ "$BROWSER_TYPE" != "firefox" ]]; then
    echo -e "${ERROR}ERROR: Invalid browser type \"$BROWSER_TYPE\"; expected either chromium or firefox${NC}"
    exit 1
    fi

    echo


    # Giving the browser permission to bypass the sandbox
    echo -e "${INFO}Giving your browser permission to run programs outside the sandbox${NC}"
    flatpak override --user --talk-name=org.freedesktop.Flatpak "$FLATPAK_ID"


    # Creating a wrapper script for 1Password in the browser's directory
    echo -e "${INFO}Creating a wrapper script for 1Password${NC}"
    mkdir -p "$HOME/.var/app/$FLATPAK_ID/data/bin"
    cat <<EOF > "$HOME/.var/app/$FLATPAK_ID/data/bin/1password-wrapper.sh"
    #!/bin/bash
    if [ "\${container-}" = flatpak ]; then
    flatpak-spawn --host /opt/1Password/1Password-BrowserSupport "\$@"
    else
    /opt/1Password/1Password-BrowserSupport "\$@"
    fi
    EOF
    chmod +x "$HOME/.var/app/$FLATPAK_ID/data/bin/1password-wrapper.sh"


    # Creating a Native Messaging Hosts file
    echo -e "${INFO}Creating a Native Messaging Hosts file for the 1Password extension to tell the browser to use the wrapper script${NC}"

    # Find the Native Messaging Hosts directory
    if [[ "$BROWSER_TYPE" = "chromium" ]]; then
    NATIVE_MESSAGING_HOSTS_DIR=$(find "$HOME/.var/app/$FLATPAK_ID/config" -maxdepth 3 -type d -name "NativeMessagingHosts" 2>/dev/null)
    elif [[ "$BROWSER_TYPE" = "firefox" ]]; then
    shopt -s dotglob
    for dir in "$HOME/.var/app/$FLATPAK_ID"/*; do
    if is_firefox_dir "$dir"; then
    NATIVE_MESSAGING_HOSTS_DIR="$dir"/native-messaging-hosts
    break
    fi

    for subdir in "$dir"/*; do
    if is_firefox_dir "$subdir"; then
    # Firefox, for example, puts profiles in .mozilla/firefox, but it puts native-messaging-hosts in .mozilla.
    NATIVE_MESSAGING_HOSTS_DIR="$dir"/native-messaging-hosts
    break
    fi
    done
    done
    fi

    if [[ ! -v NATIVE_MESSAGING_HOSTS_DIR ]] || [[ -z "$NATIVE_MESSAGING_HOSTS_DIR" ]]; then
    echo -e "${ERROR}ERROR: Could not find Native Messaging Hosts directory${NC}"
    exit 1
    fi

    add_native_messaging_host() {
    local WRAPPER_PATH="$1"
    local ALLOWED_EXTENSIONS="$2"
    local NATIVE_MESSAGING_HOSTS_DIR="$3"

    # Create the file
    if [[ ! -d $NATIVE_MESSAGING_HOSTS_DIR ]]; then
    echo -e "${INFO}Creating Native Messaging Hosts directory at $NATIVE_MESSAGING_HOSTS_DIR${NC}"
    mkdir -p "$NATIVE_MESSAGING_HOSTS_DIR"
    fi

    cat <<EOF > "$NATIVE_MESSAGING_HOSTS_DIR/com.1password.1password.json"
    {
    "name": "com.1password.1password",
    "description": "1Password BrowserSupport",
    "path": "$WRAPPER_PATH",
    "type": "stdio",
    $ALLOWED_EXTENSIONS
    }
    EOF
    }

    WRAPPER_PATH="$HOME/.var/app/$FLATPAK_ID/data/bin/1password-wrapper.sh"
    if [[ "$BROWSER_TYPE" = "chromium" ]]; then
    add_native_messaging_host "$WRAPPER_PATH" "$ALLOWED_EXTENSIONS_CHROMIUM" "$NATIVE_MESSAGING_HOSTS_DIR"
    elif [[ "$BROWSER_TYPE" = "firefox" ]]; then
    add_native_messaging_host "$WRAPPER_PATH" "$ALLOWED_EXTENSIONS_FIREFOX" "$NATIVE_MESSAGING_HOSTS_DIR"
    BROWSERS_NOT_USING_MOZILLA=("org.mozilla.firefox" "io.gitlab.librewolf-community" "net.waterfox.waterfox")
    if [[ " ${BROWSERS_NOT_USING_MOZILLA[*]} " =~ [[:space:]]${FLATPAK_ID}[[:space:]] ]]; then
    echo -e "${INFO}Skipping adding to $HOME/.mozilla/native-messaging-hosts/com.1password.1password.json${NC}"
    else
    echo "Some browsers, like Floorp and Zen, need the file in ~/.mozilla instead of in their own sandbox. This requires replacing the existing file $HOME/.mozilla/native-messaging-hosts/com.1password.1password.json with a custom one. Then, to prevent 1Password overwriting it, the file needs to be marked as read-only using chattr +i on it."
    echo -n "Do you want to continue? This will require sudo privileges. (Y/n) "
    read -r CONTINUE
    if [[ "$CONTINUE" = "N" ]] || [[ "$CONTINUE" = "n" ]]; then
    echo -e "${INFO}Skipping${NC}"
    else
    cp "$HOME/.var/app/$FLATPAK_ID/data/bin/1password-wrapper.sh" "$HOME/.mozilla/native-messaging-hosts/1password-wrapper.sh"
    flatpak override --user --filesystem="$HOME/.mozilla/native-messaging-hosts" "$FLATPAK_ID"

    WRAPPER_PATH="$HOME/.mozilla/native-messaging-hosts/1password-wrapper.sh" # For browsers that need the file in ~/.mozilla, like Zen and Floorp
    NATIVE_MESSAGING_HOSTS_DIR="$HOME/.mozilla/native-messaging-hosts"
    add_native_messaging_host "$WRAPPER_PATH" "$ALLOWED_EXTENSIONS_FIREFOX" "$NATIVE_MESSAGING_HOSTS_DIR"

    echo -e "${INFO}Marking $HOME/.mozilla/native-messaging-hosts/com.1password.1password.json as read-only using chattr +i. To undo, run this command:${NC}"
    echo -e "${INFO}sudo chattr -i $HOME/.mozilla/native-messaging-hosts/com.1password.1password.json${NC}"
    sudo chattr +i "$HOME/.mozilla/native-messaging-hosts/com.1password.1password.json" # Prevent 1Password from overwriting the file
    fi
    fi
    fi

    echo


    # Add flatpak-session-helper to custom_allowed_browsers list (needs root)
    echo -e "${INFO}Adding Flatpaks to the list of supported browsers in 1Password${NC}"
    echo "Note: This requires sudo permissions. If this doesn't work, append flatpak-session-helper to the file /etc/1password/custom_allowed_browsers"
    if [[ ! -d /etc/1password ]]; then
    echo -e "${INFO}Creating directory /etc/1password${NC}"
    sudo mkdir /etc/1password
    fi
    if grep -q 'flatpak-session-helper' /etc/1password/custom_allowed_browsers; then
    echo -e "${WARN}Already added to allowed browsers${NC}"
    else
    echo -e "${INFO}Adding to allowed browsers${NC}"
    echo 'flatpak-session-helper' | sudo tee -a /etc/1password/custom_allowed_browsers >/dev/null
    fi


    # Done
    if grep -q 'flatpak-session-helper' /etc/1password/custom_allowed_browsers; then
    echo -e "${SUCCESS}Success! 1Password should now work in your Flatpak browser.${NC}"
    echo "Now, restart both your browser and 1Password."
    else
    echo -e "${ERROR}ERROR: Could not add to allowed browsers${NC}"
    exit 1
    fi
    81 changes: 81 additions & 0 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,81 @@
    This script will automatically add support for 1Password to integrate with Flatpak web browsers on Linux. I haven't tested every browser, so add a comment if it doesn't work for your browser.

    Note: The 1Password app itself needs to be installed as a native package.

    To use this script, follow these steps:
    1. Download the script.
    2. Open your terminal in the directory that you downloaded the script to. For example, if it's in your Downloads folder, run `cd Downloads` after opening your terminal.
    3. Mark the script as executable using the command `chmod +x 1password-flatpak-browser-integration.sh`.
    4. Run the script using the command `./1password-flatpak-browser-integration.sh`.
    5. When it asks, enter the Flatpak application ID of your browser, then press Enter. If it's not listed, the easiest way to find it is to run `flatpak list --app --columns=application | grep -i <browser name>`, replacing `<browser name>` with the name of your browser.
    6. Restart both 1Password and your browser.

    This is generally made following [this guide](https://www.1password.community/discussions/1password/flatpak-browser-and-native-desktop-app/108438), but I'll add some further explanation as to how it works here.

    # Native Messaging Hosts

    Web browsers communicate with native applications using something called "Native Messaging" ([Firefox](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Native_messaging), [Chrome](https://developer.chrome.com/docs/extensions/develop/concepts/native-messaging)). This has three components:
    1. The extension specifies what native application it wants to communicate with. For example, the 1Password extension says that it supports the com.1password.1password native host.
    2. The application places a JSON file in a specific directory of the browser (`~/.config/google-chrome/NativeMessagingHosts` for a native installation of Chrome and `~/.mozilla/native-messaging-hosts` for native Firefox). This JSON file tells the browser what to do when the extension calls that native host, and it specifies a list of extension IDs so that only certain extensions can use it. This is what it looks like for 1Password:
    <details>
    <summary>1Password Native Host JSON</summary>

    ### Chrome
    ```json
    {
    "name": "com.1password.1password",
    "description": "1Password BrowserSupport",
    "path": "/usr/lib/opt/1Password/1Password-BrowserSupport",
    "type": "stdio",
    "allowed_origins": [
    "chrome-extension://hjlinigoblmkhjejkmbegnoaljkphmgo/",
    "chrome-extension://gejiddohjgogedgjnonbofjigllpkmbf/",
    "chrome-extension://khgocmkkpikpnmmkgmdnfckapcdkgfaf/",
    "chrome-extension://aeblfdkhhhdcdjpifhhbdiojplfjncoa/",
    "chrome-extension://dppgmdbiimibapkepcbdbmkaabgiofem/"
    ]
    }
    ```

    ### Firefox
    ```json
    {
    "name": "com.1password.1password",
    "description": "1Password BrowserSupport",
    "path": "/usr/lib/opt/1Password/1Password-BrowserSupport",
    "type": "stdio",
    "allowed_extensions": [
    "{0a75d802-9aed-41e7-8daa-24c067386e82}",
    "{25fc87fa-4d31-4fee-b5c1-c32a7844c063}",
    "{d634138d-c276-4fc8-924b-40a0ea21d284}"
    ]
    }
    ```
    </details>
    3. That JSON file specifies an executable file on the host system, which the browser runs when the extension triggers it. This is usually `/usr/lib/opt/1Password/1Password-BrowserSupport` on Linux, which is inaccessible from Flatpaks.

    This normally works well. The problem is that, since Flatpaks are sandboxed, they can't access either the JSON file or the executable on the host. To resolve that, we need to bypass the sandbox.

    # Bypassing the Flatpak Sandbox

    First, we need to allow the browser to access the JSON file. The easiest way is to just put the file inside the sandbox rather than allowing the browsers to bypass the sandbox, so that's what this script does in most cases (see Complications for when we don't). This just involves putting a JSON file in `~/.var/app/<browser ID>/config/<browser name>/NativeMessagingHosts` on Chromium and `~/.var/app/<browser ID>/.<browser name>/native-messaging-hosts` on Firefox (though every fork does things differently; see Complications).

    Next, we need to allow the browser to run the host command. This has three parts:
    1. To allow the app to run commands, we need to grant it permission to talk on the `org.freedesktop.Flatpak` bus using either Flatseal or this command: `flatpak override --user --talk-name=org.freedesktop.Flatpak <browser ID>`
    2. Now, it can run terminal commands by prepending `flatpak spawn --host` to them. However, the JSON file that 1Password creates doesn't have that; it just runs `/opt/1Password/1Password-BrowserSupport`. To fix this, we need to create a custom shell script inside the Flatpak sandbox with these contents:
    ```bash
    #!/bin/bash
    flatpak-spawn --host /opt/1Password/1Password-BrowserSupport "$@"
    ```
    3. We then need to tell the JSON file to run this script instead of the default 1Password-BrowserSupport binary. To do this, we just replace `/usr/lib/opt/1Password/1Password-BrowserSupport` with `<home directory>/.var/app/<browser ID>/data/bin/1password-wrapper.sh` (or wherever you put the script) in the JSON file.

    # Complications

    Firefox forks have several different places where the native-messaging-hosts directory needs to be located:
    1. In the same directory where browser profiles are stored, such as `~/.var/app/io.gitlab.librewolf-community/.librewolf`
    2. In the parent directory to the directory where profiles are stored, such as `~/.var/app/org.mozilla.firefox/.mozilla` (and profiles are stored in `~/.var/app/org.mozilla.firefox/.mozilla/firefox`)
    3. In the `~/.mozilla` directory of the host

    The first two places are somewhat annoying to find but not too difficult, but the third causes problems. Since it's on the host, the Flatpak doesn't naturally have access to it, so we need to give it permission to access the `~/.mozilla/native-messaging-hosts` directory. Then, since this would also be used by native installations of browsers like Firefox, the script needs to be reconfigured to detect if it's being run from a Flatpak container and choose whether or not to run `flatpak-spawn --host` accordingly. Finally, the JSON file would usually be overwritten by 1Password every time it starts, so we need to mark it as read-only using `chattr +i`.

    Another difficulty is finding the directory where the native messaging host JSON should go. Chromium-based browsers put it in `~/.var/app/<browser ID>/config/<browser name>/NativeMessagingHosts` or `~/.var/app/<browser ID>/config/<company name>/<browser name>/NativeMessagingHosts`. Luckily, the NativeMessagingHosts directory is already created, so we just have to run a `find` command to locate it. Firefox-based browsers don't create their `native-messaging-hosts` folder automatically, so we need to locate the `profiles.ini` file and derive the location from there.