Token substitution lets you store secrets and environment-specific values in your pipeline's secret store rather than in your configuration YAML files. The publish pipeline replaces {#[TOKEN_NAME]#} placeholders in configuration.<env>.yaml with the actual values before running apiops publish.
This feature is compatible with APIOps Toolkit configuration files — users migrating from APIOps Toolkit can use their existing configuration files without modification.
-
Define placeholders in your
configuration.<env>.yamlusing the{#[TOKEN_NAME]#}syntax:namedValues: - name: my-api-secret properties: displayName: my-api-secret secret: true value: "{#[PROD_SECRET_VALUE]#}" - name: backend-url properties: displayName: backend-url value: "{#[BACKEND_API_URL]#}"
-
Store actual values in your pipeline's secret store (GitHub Actions Secrets or Azure DevOps variable groups).
-
Token substitution runs automatically as a pipeline step before
apiops publish. Placeholders are replaced with the actual values — the secrets are never committed to the repository.
The substitution follows this pattern:
{#[TOKEN_NAME]#} → value of environment variable TOKEN_NAME
apiops init generates a substitution step in each environment's publish job:
- name: Substitute tokens in configuration.prod.yaml
uses: cschleiden/replace-tokens@v1.3
with:
tokenPrefix: '{#['
tokenSuffix: ']#}'
files: '["configuration.prod.yaml"]'
env:
# Map pipeline secrets/variables to environment variables so that
# {#[TOKEN_NAME]#} placeholders in configuration.prod.yaml are replaced
# with their actual values before the publish step runs. Example:
# MY_SECRET: ${{ secrets.MY_SECRET }}Important
The environment variable name must exactly match the token name inside {#[...]#}. Token names are case-sensitive.
-
Add secrets to your GitHub environment:
- Go to Settings → Environments → prod → Add secret
- Add a secret for each token (e.g.,
PROD_SECRET_VALUE)
-
Map secrets to env vars in the substitution step's
env:block as shown above. -
Define placeholders in
configuration.prod.yamlusing the matching token names. -
The substitution step runs during the publish job and replaces the placeholders before
apiops publishis called.
configuration.prod.yaml:
namedValues:
- name: payment-api-key
properties:
displayName: payment-api-key
secret: true
value: "{#[PAYMENT_API_KEY]#}"GitHub environment secret: PAYMENT_API_KEY = sk-live-abc123...
Workflow env: mapping:
env:
PAYMENT_API_KEY: ${{ secrets.PAYMENT_API_KEY }}Result: the placeholder {#[PAYMENT_API_KEY]#} is replaced with sk-live-abc123... before publish.
Important
The Replace Tokens extension must be installed in your Azure DevOps organization.
You can install it from Marketplace or via CLI:
az devops extension install --publisher-id qetza --extension-id replacetokens
The replacetokens task automatically reads from pipeline variables (including those from variable groups). Add your secret values as variables in the apim-<env> variable group:
- Go to Pipelines → Library → apim<env> (e.g.,
apim-prod) - Add a variable for each token (e.g.,
PROD_SECRET_VALUE) - Check "Keep this value secret" to mark it as a secret variable
The substitution task will automatically replace {#[PROD_SECRET_VALUE]#} with the variable value from the group.
- Install the Replace Tokens extension in your Azure DevOps organization if not already present.
az devops extension install --publisher-id qetza --extension-id replacetokens-
Add secret variables to your variable group:
- Go to Pipelines → Library → apim<env> (e.g.,
apim-prod) - Add each token as a secret variable (e.g.,
PROD_SECRET_VALUE)
- Go to Pipelines → Library → apim<env> (e.g.,
-
Define placeholders in
configuration.prod.yamlusing matching variable names. -
The substitution step runs automatically before the publish task.
configuration.prod.yaml:
backends:
- name: order-service
properties:
url: "{#[ORDER_SERVICE_URL]#}"
description: Order processing backendVariable group apim<env> (e.g., apim-prod):
| Variable | Value | Secret |
|---|---|---|
ORDER_SERVICE_URL |
https://orders.contoso.com/api |
✓ |
Result: {#[ORDER_SERVICE_URL]#} is replaced with https://orders.contoso.com/api before publish.
If you are migrating from APIOps Toolkit, your existing configuration.<env>.yaml files that use {#[TOKEN_NAME]#} placeholders work without modification. The same syntax is supported, using the same token prefix/suffix and the same pipeline extensions.
namedValues:
- name: subscription-key
properties:
displayName: subscription-key
secret: true
value: "{#[SUBSCRIPTION_KEY]#}"backends:
- name: inventory-api
properties:
url: "{#[INVENTORY_API_BASE_URL]#}"namedValues:
- name: db-connection
properties:
value: "{#[DB_CONNECTION_STRING]#}"
- name: auth-secret
properties:
secret: true
value: "{#[AUTH_SECRET_KEY]#}"
backends:
- name: payment-service
properties:
url: "{#[PAYMENT_SERVICE_URL]#}"Use separate configuration.<env>.yaml files (e.g., configuration.dev.yaml, configuration.prod.yaml) each referencing the same token names. The pipeline substitutes values from the environment-specific secret store, so {#[API_KEY]#} resolves to the dev key in dev and the prod key in prod.
{#[TOKEN_NAME]#}placeholders are committed to your repository — actual secret values are never stored in YAML files.- Use your pipeline platform's secret storage (GitHub Actions Secrets or Azure DevOps secret variables) to store the actual values.
- Substitution happens at pipeline runtime before
apiops publishruns.
- Environment Overrides — merge environment-specific configuration before publishing
- GitHub Actions Integration — full GitHub Actions pipeline guide
- Azure DevOps Integration — full Azure DevOps pipeline guide
- apiops init — generate pipeline scaffolding