diff --git a/docs/admin/security/secrets.md b/docs/admin/security/secrets.md
index ed658b0475..98d90fd9d8 100644
--- a/docs/admin/security/secrets.md
+++ b/docs/admin/security/secrets.md
@@ -5,9 +5,11 @@ more information about how to use secrets and other security tips, visit our
guide to
[security best practices](../../tutorials/best-practices/security-best-practices.md#secrets).
-This article explains how to use secrets in a workspace. To authenticate the
-workspace provisioner, see the
+Use this guide to configure how templates make secrets available to Coder
+workspaces. To authenticate workspace provisioners with Coder, see the
provisioners documentation.
+For secret values that developers manage themselves, see
+[User secrets](../../user-guides/user-secrets.md).
## Before you begin
@@ -42,51 +44,12 @@ Users can view their public key in their account settings:
> SSH keys are never stored in Coder workspaces, and are fetched only when
> SSH is invoked. The keys are held in-memory and never written to disk.
-## User Secrets
+## User secrets (Early Access)
-User secrets let each user store their own secret values in Coder and make
-them available in workspaces without adding those values to template code.
-They are a good fit for per-user credentials such as API keys, cloud
-credentials, or other values that should follow a user across workspaces.
-
-Use the CLI to create and manage user secrets:
-
-```sh
-# Create a secret from stdin and inject it into workspaces as an environment
-# variable.
-printf %s "$API_KEY" | coder secret create api-key \
- --description "API key for workspace tools" \
- --env API_KEY
-
-# Create a secret from stdin and inject it into a file in your workspace.
-printf %s "$TOOL_CONFIG_CONTENTS" | coder secret create tool-config \
- --description "Tool configuration" \
- --file ~/.config/tool/config.json
-
-# List all of your secrets.
-coder secret list
-
-# Show a single secret by name.
-coder secret list api-key
-
-# Delete a secret you no longer need.
-coder secret delete api-key
-```
-
-Use `--env` to inject a secret into your workspaces as an environment
-variable. Use `--file` to inject it as a file in the workspace. File
-paths must start with `~/` or `/`. Provide a secret value with `--value`,
-or non-interactive stdin (pipe or redirect). Stdin is read verbatim. This
-means `echo "$API_KEY" | ...` usually adds a trailing newline to the stored
-value. Prefer `printf %s "$API_KEY" | ...` or `echo -n "$API_KEY" | ...`
-when you do not want that newline.
-
-You can update a secret later with `coder secret update`, including rotating
-the value or clearing an injection target by passing an empty string. Use
-`coder secret delete` to remove a secret entirely. The secret value itself is
-never returned by the API or CLI list output. For full command details, see
-[`coder secret`](../../reference/cli/secret.md) and the
-[Secrets API reference](../../reference/api/secrets.md).
+User secrets are developer-managed values that Coder injects at workspace start.
+If a user secret targets the same environment variable name or file path as a
+template-provided variable or file, Coder injects the user secret into that
+workspace. See the [User secrets guide](../../user-guides/user-secrets.md).
## Dynamic Secrets
diff --git a/docs/manifest.json b/docs/manifest.json
index 32d777824d..2042be727d 100644
--- a/docs/manifest.json
+++ b/docs/manifest.json
@@ -366,6 +366,13 @@
"description": "Personalize your environment with dotfiles",
"path": "./user-guides/workspace-dotfiles.md",
"icon_path": "./images/icons/art-pad.svg"
+ },
+ {
+ "title": "User secrets",
+ "description": "Store secret values in Coder and automatically inject them into workspaces",
+ "path": "./user-guides/user-secrets.md",
+ "icon_path": "./images/icons/secrets.svg",
+ "state": ["early access"]
}
]
},
diff --git a/docs/user-guides/user-secrets.md b/docs/user-guides/user-secrets.md
new file mode 100644
index 0000000000..1eb3b225ba
--- /dev/null
+++ b/docs/user-guides/user-secrets.md
@@ -0,0 +1,146 @@
+# User secrets (Early Access)
+
+User secrets let you store secret values in Coder and make them available in
+every workspace you own.
+
+> [!NOTE]
+> User secrets are in Early Access and may change. For more information, see
+> [feature stages](../install/releases/feature-stages.md#early-access-features).
+
+## How user secrets work
+
+Each user secret has:
+
+- A name, used to manage the secret with the CLI or REST API.
+- A value, which contains the sensitive content.
+- An optional description.
+- An optional environment variable target, file target, or both.
+
+A secret without an environment variable target or file target is stored, but is
+not injected into workspaces.
+
+User secrets apply to all workspaces that you own. Coder injects user secrets
+when a workspace starts. If you create, update, or delete a secret while a
+workspace is running, restart the workspace before relying on that change.
+
+Environment variable secrets are available to startup scripts and workspace
+sessions. File secrets are written before startup scripts run.
+
+Secret values are omitted from CLI output and REST API responses after you
+create or update them.
+
+> [!WARNING]
+> Anyone with shell or file access to a workspace can read secrets injected into
+> that workspace. Do not share a workspace that has injected secrets with users
+> who should not access those values.
+
+## Create a secret
+
+Use `coder secret create ` to create a user secret. For sensitive values,
+provide the value through non-interactive stdin with a pipe or redirect. This
+keeps the value out of your shell history and process arguments.
+
+### Create an environment variable secret
+
+Use `--env` to inject a secret into your workspaces as an environment variable.
+The secret is available under the environment variable name you provide. User
+secret environment variables take precedence over template-defined environment
+variables with the same name, including variables set with `coder_env`.
+
+```sh
+echo -n "$API_KEY" | coder secret create api-key \
+ --description "API key for workspace tools" \
+ --env API_KEY
+```
+
+### Create a file secret
+
+Use `--file` to inject a secret as a file in your workspaces. File paths must
+start with `~/` or `/`.
+
+```sh
+coder secret create tool-config \
+ --description "Tool configuration" \
+ --file ~/.config/tool/config.json \
+ < ./tool-config.json
+```
+
+Coder creates parent directories as needed. If the file already exists, including
+a file created by a template or image, Coder updates the contents and preserves
+the existing permissions.
+
+### Create a secret with environment variable and file targets
+
+You can inject the same secret as both an environment variable and a file:
+
+```sh
+echo -n "$TOKEN" | coder secret create service-token \
+ --description "Service token for workspace tools" \
+ --env SERVICE_TOKEN \
+ --file ~/.config/service/token
+```
+
+### Use `--value`
+
+You can also provide a secret value with `--value`:
+
+```sh
+coder secret create api-key \
+ --value "$API_KEY" \
+ --description "API key for workspace tools" \
+ --env API_KEY
+```
+
+For sensitive values, prefer stdin because `--value` can expose the secret in
+shell history or process arguments.
+
+Stdin is read verbatim. If the source file ends with a trailing newline, Coder
+stores that newline as part of the secret value. Use `echo -n` when you do not
+want to store a trailing newline:
+
+```sh
+echo -n "$API_KEY" | coder secret create api-key --env API_KEY
+```
+
+## Update a secret
+
+Use `coder secret update` to update a secret value, description, environment
+variable target, or file target. At least one of `--value`, `--description`,
+`--env`, or `--file` must be specified.
+
+```sh
+# Update a secret value.
+echo -n "$NEW_API_KEY" | coder secret update api-key
+
+# Change the environment variable target.
+coder secret update api-key --env NEW_API_KEY
+
+# Clear the file injection target while keeping the secret.
+coder secret update api-key --file ""
+```
+
+## List and delete secrets
+
+List, show, and delete your secrets with the `coder secret` CLI:
+
+```sh
+# List all of your secrets.
+coder secret list
+
+# Show a single secret by name.
+coder secret list api-key
+
+# Delete a secret you no longer need.
+coder secret delete api-key
+```
+
+Deleting a secret removes it from Coder and stops Coder from injecting it during
+future workspace starts. Deleting a secret does not remove the value from
+running processes or delete files that were already written in existing
+workspaces.
+
+The list and show commands return secret metadata only. They never return the
+secret value.
+
+For full command details, see [`coder secret`](../reference/cli/secret.md) and
+the [Secrets API reference](../reference/api/secrets.md).