TCA integration
nr-vault provides a custom TCA field type that allows any TYPO3 extension to store sensitive data (API keys, credentials, tokens) securely in the vault instead of plaintext in the database.
Table of contents
Quick start
Step 1: Add dependency
Add nr-vault as a dependency in your extension's composer.:
{
"require": {
"netresearch/nr-vault": "^1.0"
}
}
Step 2: Configure TCA field
Use the vaultSecret renderType in your TCA configuration:
<?php
return [
'ctrl' => [
'title' => 'My Extension Settings',
// ... other ctrl settings
],
'columns' => [
'api_key' => [
'label' => 'API Key',
'config' => [
'type' => 'input',
'renderType' => 'vaultSecret',
'size' => 30,
],
],
],
];
Step 3: Add database column
Add the column to your extension's ext_:
CREATE TABLE tx_myext_settings (
api_key varchar(255) DEFAULT '' NOT NULL
);
The column stores the vault identifier, not the actual secret.
Step 4: Retrieve secrets in code
Use the
Vault utility to retrieve actual secret values:
use Netresearch\NrVault\Utility\VaultFieldResolver;
class MyService
{
public function callExternalApi(array $settings): void
{
// Resolve vault identifiers to actual values
$resolved = VaultFieldResolver::resolveFields(
$settings,
['api_key', 'api_secret']
);
// Now $resolved['api_key'] contains the actual secret
$client->authenticate($resolved['api_key']);
}
}
Using the TCA helper
For cleaner TCA configuration, use the
Vault:
<?php
use Netresearch\NrVault\TCA\VaultFieldHelper;
return [
'columns' => [
'api_key' => VaultFieldHelper::getFieldConfig([
'label' => 'API Key',
'description' => 'Your API authentication key',
'size' => 30,
]),
// Secure field with common defaults (exclude: true, l10n_mode: exclude)
'api_secret' => VaultFieldHelper::getSecureFieldConfig(
'API Secret',
['required' => true]
),
],
];
Available options
| Option | Type | Description |
|---|---|---|
label | string | Field label. |
description | string | Field description/help text. |
size | int | Input field size (default: 30). |
required | bool | Whether field is required (default: false). |
placeholder | string | Placeholder text. |
displayCond | string | TCA display condition. |
l10n_mode | string | Localization mode. |
exclude | bool | Exclude from non-admin access. |
FlexForm integration
Vault secrets also work in FlexForm fields:
<T3DataStructure>
<sheets>
<settings>
<ROOT>
<el>
<apiKey>
<label>API Key</label>
<config>
<type>input</type>
<renderType>vaultSecret</renderType>
<size>30</size>
</config>
</apiKey>
</el>
</ROOT>
</settings>
</sheets>
</T3DataStructure>
Resolve FlexForm secrets using
Flex:
use Netresearch\NrVault\Utility\FlexFormVaultResolver;
use TYPO3\CMS\Core\Service\FlexFormService;
class MyPlugin
{
public function __construct(
private readonly FlexFormService $flexFormService,
) {}
public function processSettings(array $contentElement): array
{
$settings = $this->flexFormService->convertFlexFormContentToArray(
$contentElement['pi_flexform']
);
// Resolve specific fields
return FlexFormVaultResolver::resolveSettings(
$settings,
['apiKey', 'apiSecret']
);
// Or resolve all vault identifiers automatically
return FlexFormVaultResolver::resolveAll($settings);
}
}
VaultFieldResolver API
The
Vault class provides utilities for working with
vault-backed TCA fields.
resolveFields()
Resolve specific fields in a data array:
$resolved = VaultFieldResolver::resolveFields(
$data, // Array with potential vault identifiers
['field1'], // Fields to resolve
false // Throw on error (default: false)
);
resolve()
Resolve a single vault identifier (UUID v7 format):
// TCA field identifiers use UUID v7 format
$secret = VaultFieldResolver::resolve('01937b6e-4b6c-7abc-8def-0123456789ab');
resolveRecord()
Automatically resolve all vault fields in a record based on TCA:
$resolved = VaultFieldResolver::resolveRecord('tx_myext_settings', $record);
isVaultIdentifier()
Check if a value is a vault identifier:
if (VaultFieldResolver::isVaultIdentifier($value)) {
// This is a vault identifier
}
getVaultFieldsForTable()
Get list of vault field names for a table:
$fields = VaultFieldResolver::getVaultFieldsForTable('tx_myext_settings');
// Returns: ['api_key', 'api_secret']
How it works
Data flow
- Form display: The
Vaultrenders an obfuscated password field with reveal/copy buttons.Secret Element -
Form submit: The
Dataintercepts the form data:Handler Hook - Extracts the secret value from the form.
- Generates a UUID v7 identifier (time-ordered, unique).
- Stores the secret in the vault with metadata (table, field, uid).
- Saves only the UUID identifier to the database.
- Runtime retrieval: Your code uses
Vaultto look up the actual secret from the vault using the UUID.Field Resolver
Identifier format
TCA and FlexForm fields use UUID v7 identifiers:
01937b6e-4b6c-7abc-8def-0123456789ab
UUID v7 provides:
- Time-ordering: Better B-tree index performance in databases.
- Uniqueness: Collision-free without central coordination.
- Security: Does not expose table/field names in the identifier.
The source context (table, field, uid) is stored as metadata in the vault, not in the identifier itself.
Tip
See ADR-001: UUID v7 for secret identifiers for the full rationale behind this design decision.
Record operations
- Create: New vault secret is stored automatically.
- Update: Secret is rotated (maintains audit trail).
- Delete: Vault secret is removed when record is deleted.
- Copy: Vault secret is copied to new record.
Security considerations
Access control
Vault secrets inherit the access control of the record they belong to. If a backend user can edit the record, they can update the vault secret.
The reveal button requires explicit user action and is logged.
Audit trail
All vault operations are logged:
- Secret creation.
- Secret reads (via reveal button).
- Secret updates.
- Secret deletion.
Review the audit log in the backend module under Admin Tools > Vault > Audit Log.
No plaintext in database
Only vault identifiers are stored in your extension's database tables. The actual secrets are encrypted with AES-256-GCM in the vault.
Migration
To migrate existing plaintext credentials to vault storage:
- Add the
renderTypeto your existing TCA field configuration. -
Run the migration command:
Migrate existing field to vaultvendor/bin/typo3 vault:migrate-field tx_myext_settings api_keyCopied!
This will:
- Read existing plaintext values.
- Store them securely in the vault.
- Update records with vault identifiers.
Attention
Always backup your database before running migrations.