> ## Documentation Index
> Fetch the complete documentation index at: https://www.1password.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Use the 1Password SSH agent with WSL

export const CodeResult = ({children, resultLang, wrap, expandable}) => {
  const parseChildren = () => {
    let language = "text";
    let codeContent = "";
    const extractText = node => {
      if (typeof node === "string") {
        return node;
      }
      if (Array.isArray(node)) {
        return node.map(extractText).join("");
      }
      if (node?.props?.children) {
        return extractText(node.props.children);
      }
      return "";
    };
    const extractLanguage = node => {
      if (!node) return null;
      if (node.props?.className) {
        const className = node.props.className;
        const langMatch = className.match(/language-(\w+)/);
        if (langMatch) {
          return langMatch[1];
        }
      }
      if (node.props?.["data-language"]) {
        return node.props["data-language"];
      }
      if (node.props?.language) {
        return node.props.language;
      }
      return null;
    };
    if (typeof children === "string") {
      codeContent = children;
    } else if (Array.isArray(children)) {
      codeContent = extractText(children);
      for (const child of children) {
        const detectedLang = extractLanguage(child);
        if (detectedLang) {
          language = detectedLang;
          break;
        }
      }
    } else if (children?.props) {
      const detectedLang = extractLanguage(children);
      if (detectedLang) {
        language = detectedLang;
      }
      codeContent = extractText(children);
    }
    const parts = codeContent.split("#code-result");
    if (parts.length < 2) {
      return {
        command: codeContent.trim(),
        result: null,
        language,
        defaultOpen: false
      };
    }
    const resultText = parts[1].trim();
    const defaultOpen = resultText.startsWith("open");
    const cleanResult = defaultOpen ? resultText.slice(4).trim() : resultText;
    return {
      command: parts[0].trim(),
      result: cleanResult,
      language,
      defaultOpen
    };
  };
  const {command, result, language, defaultOpen} = parseChildren();
  const [isOpen, setIsOpen] = useState(defaultOpen);
  if (!result) {
    return children;
  }
  return <div className="codeblock_accordion not-prose mb-4">
      {}
      <div className="[&>*]:!mb-0 [&>*]:!rounded-b-none">
        <CodeBlock language={language} children={command} wrap={wrap} expandable={expandable} />
      </div>

      {}
      <div className="see_results_container border-t-0 bg-gray-100/80 dark:bg-gray-800/80 overflow-hidden" style={{
    marginTop: "-0.25rem"
  }}>
        <button onClick={() => setIsOpen(!isOpen)} className="w-full px-4 py-2.5 flex items-center gap-1 text-left text-[14px] font-medium text-gray-600 dark:text-gray-400 hover:text-gray-800 dark:hover:text-gray-200 hover:bg-gray-200/60 dark:hover:bg-gray-700/60 transition-all duration-150" aria-expanded={isOpen}>
          {isOpen ? <Icon icon="caret-down" size="14" iconType="solid" /> : <Icon icon="caret-right" size="14" iconType="solid" />}

          <span>See result...</span>
        </button>

        {isOpen && <div className="[&>*]:!mt-0 [&>*]:!rounded-t-none border-t border-[var(--op-border-ui)] dark:border-[var(--op-border-ui-dark)]">
            <CodeBlock language={resultLang || language} children={result} wrap={wrap} expandable={expandable} />
          </div>}
      </div>
    </div>;
};

export const Image = ({src, darkSrc, alt, width, border, height, round}) => {
  const classNames = ["mint-mx-4"];
  if (border) {
    classNames.push("mint-rounded-sm");
  }
  if (round) {
    classNames.push("mint-rounded-lg");
  }
  const style = {};
  if (width) style.width = typeof width === "number" ? `${width}px` : width;
  if (height) style.height = typeof height === "number" ? `${height}px` : height;
  return darkSrc ? <>
      <img src={src} alt={alt} className={[...classNames, "dark:hidden"].join(" ")} style={Object.keys(style).length > 0 ? style : undefined} />
      <img src={darkSrc} alt={alt} className={[...classNames, "hidden dark:block"].join(" ")} style={Object.keys(style).length > 0 ? style : undefined} onError={e => {
    e.target.src = src;
  }} />
    </> : <img src={src} alt={alt} className={classNames.join(" ")} style={Object.keys(style).length > 0 ? style : undefined} />;
};

export const Small = ({children}) => {
  return <small>{children}</small>;
};

The 1Password Windows Subsystem for Linux (WSL) integration allows you to authenticate SSH and Git commands and sign your Git commits within WSL using the 1Password SSH agent running on your Windows host.

The 1Password integration supports both WSL 1 and WSL 2.

## Requirements

1. [Sign up for 1Password.](https://1password.com/pricing/password-manager)
2. [Install and sign in to 1Password for Windows](https://1password.com/downloads/windows).
3. [Import or generate SSH keys in 1Password.](/ssh/manage-keys/)
4. [Set up the 1Password SSH agent](/ssh/get-started/) on your Windows host and make sure it's running.
5. [Install Windows Subsystem for Linux on Windows <Icon icon="arrow-up-right-from-square" />](https://learn.microsoft.com/windows/wsl/install) with your preferred Linux distribution.

To use [SSH Git commit signing with the 1Password WSL integration](#sign-git-commits-with-ssh), you'll also need:

* Git 2.34.0 or later.
* A 64-bit version of Windows 10 or later. Arm-powered Windows devices aren't supported.

## How the integration works

With WSL, you can [run Windows tools from the command line <Icon icon="arrow-up-right-from-square" />](https://learn.microsoft.com/windows/wsl/filesystems#run-windows-tools-from-linux), such as the Windows OpenSSH client (`ssh.exe`). The 1Password WSL integration leverages the [interoperability <Icon icon="arrow-up-right-from-square" />](https://learn.microsoft.com/windows/wsl/filesystems#interoperability-between-windows-and-linux-commands) built into WSL to forward SSH requests to the 1Password SSH agent on Windows.

Instead of forwarding SSH *agent* requests, like with standard OpenSSH agent forwarding, you can effectively forward the entire SSH request from WSL to the `ssh.exe` process running on Windows. The `ssh.exe` process then uses the 1Password SSH agent on your Windows host to authenticate the request.

This also means that any [changes to your SSH configuration](/ssh/agent/advanced) need to be made in your Windows `%USERPROFILE%/.ssh/config` file, rather than the file on your WSL instance.

## Forward an SSH request

1. Check if the 1Password SSH agent is running **on your Windows host** with the following command:

   <CodeResult>
     ```powershell theme={null}
     ssh-add.exe -l
     #code-result
     256 SHA256:2zmxMpLy5MeIx18pBUkumptKkKinlghygOvV6URe8QI Git Authentication Key (ED25519)
     ```
   </CodeResult>

   If the agent is running, a list with one or more SSH keys will be returned. These are the SSH keys you stored in 1Password that are available to use with the agent for SSH requests.

2. Check if WSL is forwarding SSH requests successfully by running the following command **in your WSL instance**:

   <CodeResult>
     ```shell theme={null}
     ssh-add.exe -l
     #code-result
     256 SHA256:2zmxMpLy5MeIx18pBUkumptKkKinlghygOvV6URe8QI Git Authentication Key (ED25519)
     ```
   </CodeResult>

   You should see the same list of SSH keys returned as you did when you ran the command on your Windows host. If you do, then WSL is forwarding your SSH requests to your Windows host.<br /><Small>[Get help](#error-command-not-found) if you don't see your SSH key(s) listed when you run the <code>ssh-add.exe -l</code> command.</Small>

3. If you see your SSH key(s) listed in WSL, try to run an SSH request, replacing `ssh` with `ssh.exe` in your command. For example:

   ```shell theme={null}
   ssh.exe -T git@github.com
   ```

You should see a prompt from 1Password to authorize the SSH request:

<div style={{textAlign: 'center'}}>
  <Image alt="SSH authorization prompt for WSL." style={{ maxWidth: "400px" }} src="/static/img/ssh/wsl-auth-prompt.png" />
</div>

You can now use the 1Password SSH agent to forward SSH requests between your Windows host and WSL instance.

## Configure Git to use `ssh.exe`

To use the 1Password SSH agent to authenticate Git commands in WSL, you can configure Git to use `ssh.exe` as the `core.sshCommand`.

To set this variable globally, run the following command in WSL:

```shell theme={null}
git config --global core.sshCommand ssh.exe
```

## Sign Git commits with SSH

<Note>
  1Password for Windows 8.11.18 and later uses a new [MSIX installer](https://support.1password.com/cs/1password-msix-installer/), which automatically [updates the app data path](#error-cannot-run). If you set up the SSH agent to authenticate Git commands in WSL prior to version 8.11.18, you'll need to follow the steps below to configure Git commit signing again.
</Note>

With Git configured to use `ssh.exe`, you can also use the integration to sign Git commits from WSL.

<CardGroup cols={2}>
  <div>
    To configure Git commit signing with SSH globally in WSL:

    1. On your Windows host, open the 1Password app, then open the SSH key you want to use.
    2. Select <Icon icon="ellipsis-v" /> > **Configure Commit Signing**.
    3. In the next window, select the checkbox to **Configure for Windows Subsystem for Linux (WSL)**, then select **Copy Snippet**.
    4. In your WSL instance, paste the snippet into your <code>\~/.gitconfig</code> file.
  </div>

  <div>
    <Image round shadow alt="The Configure Git Commit Signing window showing the checkbox to configure for WSL and the configuration snippet." src="/static/img/ssh/configure-git-commit-signing-wsl.png" style={{ maxWidth: "400px" }} />
  </div>
</CardGroup>

You can also [configure SSH signing in a single repository](/ssh/git-commit-signing#configure-commit-signing-in-a-single-repository).

1Password will make the following changes to your Git config file:

* Set `gpg.format` to `ssh`.
* Set `user.signingkey` to the public key you chose to sign commits with.
* Set `commit.gpgsign` to `true` so you don't need to include the `-S` flag with each commit. *(optional)*
* Set `gpg.ssh.program` to the SSH signer binary provided by 1Password.

After you set up Git commit signing on WSL, you can use the same steps as your Windows host to test the configuration. [Register your public key](/ssh/git-commit-signing/#step-2-register-your-public-key), then [commit some code](/ssh/git-commit-signing/#step-3-commit-and-push-your-code) and [verify your commit is signed](/ssh/git-commit-signing#step-4-verify-your-commit-signature).

## Optional: Add an alias for SSH commands

If you plan to use the 1Password SSH agent on your Windows host to authenticate SSH requests other than Git, you can optionally [create aliases in your Bash profile <Icon icon="arrow-up-right-from-square" />](https://linux.die.net/Bash-Beginners-Guide/sect_03_05.html) to use `ssh` and `ssh-add` on the command line in place of `ssh.exe` and `ssh-add.exe`.

This isn't required, but it can be convenient to use the same SSH commands across all your platforms. In your `~/.bashrc` or `~/.bash_aliases` file, add the following aliases:

```shell theme={null}
alias ssh='ssh.exe'
alias ssh-add='ssh-add.exe'
```

## Authorization model

The 1Password SSH agent uses the same [authorization model](/ssh/agent/security#authorization-model) with the WSL integration as it does on other platforms. When you approve an SSH key request for a WSL session, only the current session is authorized to use that key. If you open a new WSL session or tab, you'll be prompted to approve the SSH request again.

[Learn more about the 1Password SSH agent authorization model.](/ssh/agent/security#authorization-model)

## Troubleshooting

### Error: `command not found`

If you see a `command not found` error when you run the `ssh-add.exe -l` command in WSL, OpenSSH may not be in your `PATH`. Try to run the command again using the full executable path:

```shell theme={null}
/mnt/c/Windows/System32/OpenSSH/ssh-add.exe -l
```

If you still see an error, check if the [interoperability setting  <Icon icon="arrow-up-right-from-square" />](https://learn.microsoft.com/windows/wsl/wsl-config#interop-settings) (`[interop]`)is turned on in your WSL config file. If it is, the entry will look like this:

```text theme={null}
[interop]
enabled = true
```

If you see `enabled = false` instead, set the `enabled` value to `true`.

### Error: `cannot run`

1Password for Windows 8.11.18 and later uses an [MSIX installer](https://support.1password.com/cs/1password-msix-installer/), which updates the app data path previously used by the EXE installer.

If you configured the SSH agent to authenticate Git commands in WSL using an earlier version of the app, you may see the following error message:

```
fatal: cannot run /mnt/c/Users/<username>/AppData/Local/1Password/app/8/op-ssh-sign-wsl: No such file or directory
```

To fix the issue, you'll need to [reconfigure Git commit signing for WSL](#sign-git-commits-with-ssh). This will add the updated path to your `.gitconfig` file.

```text Deprecated path (8.11.16 and earlier) theme={null}
/mnt/c/Users/<Username>/AppData/Local/1Password/app/8/op-ssh-sign-wsl
```

```text New path (8.11.18 and later) theme={null}
/mnt/c/Users/<Username>/AppData/Local/Microsoft/WindowsApps/op-ssh-sign-wsl.exe
```

## Learn more

* [Autofill public keys](/ssh/public-key-autofill/)
* [Manage SSH keys](/ssh/manage-keys/#generate-an-ssh-key)
* [Sign Git commits](/ssh/git-commit-signing)
* [Workflow: Secure your SSH & Git workflows](/get-started/secure-ssh-git-workflows)
