The $dotsecrets
Viewtool allows passing of a secret string or character array — such as a token, key, password, etc. — via Velocity, without including sensitive data in the VTL file.
The Secrets Viewtool debuted in release 23.07. Its toolbox.xml mapping is as follows:
<tool>
<key>dotsecrets</key>
<scope>application</scope>
<class>com.dotcms.rendering.velocity.viewtools.SecretTool</class>
</tool>
General Security Notes
The handling of secrets in any context calls for care; misuse of the Secrets Viewtool can lead to exposure of sensitive data.
We recommend using the Secrets Viewtool in conjunction with a custom Scripting API endpoint or the Velocity Script Workflow Sub-Action, as these offer no opportunity for a secret to be unintentionally rendered.
When used within a Widget or Page, avoid printing $dotsecrets
anywhere it has the potential to be rendered. One easy guideline for this use case is to use the viewtool only within the parentheses of a Velocity directive. For example:
#if($userInput == $dotsecrets[$userKey])
Render this block.
#end
This ensures the secret will not appear in a user's browser session.
When using the Secrets Viewtool as part of an API call to an external application, it is important that the data retrieved from $dotsecrets
be sent directly to that external target instead of back to a browser session. While many in many contexts it is appropriate to offload API calls to a client to spare server load, this pattern is not recommended in the context of $dotsecrets
, as it virtually guarantees the secret's exposure. Instead, wrap the call in a Scripting API method; if the server handles the sensitive call and simply returns its results to the client, this presents no such risk.
Usage
App Configuration
The Secrets Viewtool interfaces with a special app called Dot Velocity Secrets, which lives under System → Apps. All keys must be stored as Custom Properties under either a specific site or the system host. No site can access the secrets of another site, though secrets stored at the system host level are accessible from any site. As a general rule, it is better to make secrets as narrowly accessible as possible; accordingly, it is best to use system host secrets only in cases where one operation affects multiple sites.
Headless Configuration
The Dot Velocity Secrets App can be configured headlessly through a special /v1/apps/dotVelocitySecretApp
REST API endpoint. To POST
to this endpoint, use the relevant site identifier as a path parameter, and include a JSON payload of properties with the following schema:
{
"property": {
"hidden": true|false,
"value": "string"
}
}
There is a single reserved property called title
, which provides a descriptive title for the Site entry within the app. Its hidden
property cannot be changed from false
.
All other properties are keys corresponding to a secret value.
Example of updating the dotCMS Demo Site:
curl -v -u admin@dotcms.com:admin -X POST https://demo.dotcms.com/api/v1/apps/dotVelocitySecretApp/48190c8c-42c4-46af-8d1a-0cd5db894797 -H "Content-Type: application/json" -d '{
"title":{"hidden":false,"value":"dotCMS demo site secrets"},
"test2":{"hidden":true,"value":"secret2"},
"test1":{"hidden":false,"value":"secret1"}
}'
Similarly, updating the System Host:
curl -v -u admin@dotcms.com:admin -X POST https://demo.dotcms.com/api/v1/apps/dotVelocitySecretApp/SYSTEM_HOST -H "Content-Type: application/json" -d '{
"title":{"hidden":false,"value":"dotCMS demo site system secrets"},
"sysSecret1":{"hidden":false,"value":"thebigsecret"}
}'
Using either of those URLs with the GET
HTTP method will simply return their properties. If you GET
the endpoint without a path parameter, it returns a list of site entries within the app, but not their individual properties.
Velocity Commands
Command | Result |
---|---|
$dotsecrets.get("foo") or $dotsecrets.foo or $dotsecrets["foo"] or $dotsecrets[$foo] | Four equivalent ways to retrieve the local site secret stored with key foo — in the last case after the declaration of #set($foo = "foo") |
$dotsecrets.getSystemSecret("foo") | Retrieves the system host secret stored with the key foo . |
$dotsecrets.getCharArray("foo") | Similar to .get("foo") , but returns the local site secret as an array of characters instead of a string. |
$dotsecrets.getCharArraySystemSecret("foo") | Similar to .getSystemSecret("foo") , but returns the system host secret as an array of characters instead of a string. |
Examples
Passing an API Key or Token in Velocity
After storing the access token in the Dot Velocity Secret App under the key myKey
, you can include it in the Authorization
header of an API call as follows:
#set($queryString = "{ \"query\":\"hello world\" }")
#set($timeout = 3000)
#set($headers = {})
$!{headers.put("Authorization", "bearer ${dotsecrets.myKey}")}
$!{headers.put("Content-type" , "application/json")}
#set($results = $json.post("https://api.example.com/endpoint", $timeout, $headers, $queryString))