How to use SecretStorage in your VSCode extensions
Published: 2021-07-14 17:41:38

There are several ways to save user data in VSCode. Until version 1.53.0 all private information used to be kept in Memento objects using [workspaceState and globalState](https://code.visualstudio.com/api/references/vscode-api#ExtensionContext) or [keystone](https://github.com/microsoft/vscode-docker/pull/2709/files), for example. Keeping passwords with tokens in a standard configuration file or using environment variables wasn’t a good idea either, because all that data could be read and cached by other extensions.

In this post, we will cover the ways of reading data from `settings.json` and `environment variables`. After that, we will create a class with minimum functionality, that is going to be responsible for keeping and giving away the keys with values from VSCode SecretStorage.
Let’s call our project `fancycolor`, for example. The whole initialization process is described in detail in [VSCode Extensions documentation](https://code.visualstudio.com/api/get-started/your-first-extension), so let’s go straight to the point here.

## settings.json

All settings from all VSCode extensions are kept in a public file `settings.json` and they all can be accessed using any other extension. For instance, from our fancycolor app, we can easily read the list of all hosts and platforms corresponding them from the configuration file of another popular app `SSH - Remote`.

```javascript
const configurationWorkspace = workspace.getConfiguration()
const sshRemotePlatform: string | undefined = configurationWorkspace.get(
  "remote.SSH.remotePlatform"
)
console.log(sshRemotePlatform)
```

The following code will display your configuration list for `SSH - Remote` extension.

```bash
Proxy {ubuntu: 'linux', home: 'linux', raspberry: 'linux'}
```

## environment variables

VSCode variables have access to all user’s environment variables by default. All the data which we saved in `.bashrc` on Linux or `User.Environment` on Windows can be received using global object `process.env`.

For example, let’s make a file `/home/ubuntu/.env` with a variable `ACCESS_TOKEN_ENV` and add it in `.bashrc`.

```bash
echo 'export ACCESS_TOKEN_ENV="d8aba3b2-fda0-414a-b867-4798b7892bb4"' >> /home/ubuntu/.env
echo "source /home/ubuntu/.env" >> /home/ubuntu/.bashrc
```

On Windows, we can do the same using Powershell.

```powershell
[System.Environment]::SetEnvironmentVariable('ACCESS_TOKEN_ENV', 'd8aba3b2-fda0-414a-b867-4798b7892bb4', [System.EnvironmentVariableTarget]::User)
```

Now let’s read it in our VSCode `fancycolor` extension

```javascript
import * as process from "process"
export const accessTokenEnv = process.env["ACCESS_TOKEN_ENV"]
console.log(accessTokenEnv)
```

We can see our token in the output.

```bash
d8aba3b2-fda0-414a-b867-4798b7892bb4
```

## SecretStorage

Nowadays SecretStorage is the best way to keep passwords, logins, tokens, and any other private information in VSCode. To demonstrate that, let’s create a simple class `AuthSettings`, where we will save `fancycolor_token`, using only necessary methods such as:

- `init` - to initialize our SecretStorage
- getter `instance`
- `storeAuthData` - to write in SecretStorage
- `getAuthData` - to get data from SecretStorage

```javascript
import { ExtensionContext, SecretStorage } from "vscode"

export default class AuthSettings {
	private static _instance: AuthSettings

	constructor(private secretStorage: SecretStorage) {}

	static init(context: ExtensionContext): void {
		/*
		Create instance of new AuthSettings.
		*/
		AuthSettings._instance = new AuthSettings(context.secrets)
	}

	static get instance(): AuthSettings {
		/*
		Getter of our AuthSettings existing instance.
		*/
		return AuthSettings._instance
	}

	async storeAuthData(token?: string): Promise<void> {
		/*
		Update values in bugout_auth secret storage.
		*/
		if (token) {
			this.secretStorage.store("fancycolor_token", token)
		}
	}

	async getAuthData(): Promise<string | undefined> {
		/*
		Retrieve data from secret storage.
		*/
		return await this.secretStorage.get("fancycolor_token")
	}
}
```

In `extensions.ts` let’s write an option which will allow us to add and extract token using commands in Command Palette.

```javascript
import * as vscode from "vscode"

import AuthSettings from "./settings"

export function activate(context: vscode.ExtensionContext) {
	// Initialize and get current instance of our Secret Storage
	AuthSettings.init(context)
	const settings = AuthSettings.instance
	
	// Register commands to save and retrieve token
	vscode.commands.registerCommand("fancycolor.setToken", async () => {
		const tokenInput = await vscode.window.showInputBox()
		await settings.storeAuthData(tokenInput)
	})
	vscode.commands.registerCommand("fancycolor.getToken", async () => {
		const tokenOutput = await settings.getAuthData()
		console.log(tokenOutput)
	})
}

export function deactivate() {}
```

The only thing left is to register commands `fancycolor.setToken` and `fancycolor.getToken` in `package.json` . Subsequently working with VSCode SecretStorage we can apply directly to a specific SecretStorage that was made for our app and will have its own `_id: 'undefined_publisher.fancycolor'`.

If you want a real-world example, [see how we use SecretStorage in the Bugout VSCode extension](https://github.com/bugout-dev/bugout-vscode).