Search the site
OPERATIONS
A backend secret that reaches client code stops the build, before it can ship in an app bundle.
A deploy stops when a secret its environment needs is missing.
ON THIS PAGE
Declare your secrets
Read a secret on the server
What the build refuses
Give a test its own secrets
Keep the application key in the OS keychain
Status
# pubspec.yaml
dartvel:
secrets:
PAYSTACK_SECRET: { required: [production, staging] }
DATABASE_URL: { required: [production] }
PUBLIC_MAPS_KEY: { scope: client, required: [production] }Copy code to clipboard
A secret is backend-only unless it says scope: client, and a client secret must start with PUBLIC_. A name that breaks either rule stops the build.
required lists the environments it must be set in. dartvel deploy --environment production refuses to start without them.
@DVBackendFunction(policy: 'Order.update')
Future<Map<String, Object?>> _refund(String reference) async {
// Backend code has no DV facade, so it reads secrets through DVSecrets.
final String key = const DVSecrets().get('PAYSTACK_SECRET'); // throws if unset
final Response response = await const DVHttp().host('paystack').post(
'/refund',
json: <String, Object?>{'transaction': reference},
headers: <String, String>{'authorization': 'Bearer $key'},
idempotencyKey: 'refund-$reference',
);
return <String, Object?>{'status': response.status};
}Copy code to clipboard
App code uses DV.Secrets. get throws when the name is unset, and maybeGet, getOr and has do not.
Values come from DVSecrets.configure, then the environment, then systemd credentials, then your .env files.
A value you have read is replaced with [redacted] in logs, crash reports and analytics events, once it is 8 characters long.
DV-SECRETS-001
Means: Client code reads a backend secret
DV-SECRETS-002
Means: Code reads a name nobody declared
DV-SECRETS-003
Means: An env file has a PUBLIC_ variable nobody declared, which would be compiled into the app
Client code means lib/ outside your backend directory.
PUBLIC_ values are compiled into env.g.dart as Env.PUBLIC_NAME. Anyone with the app can read them, so keep real keys out.
test('a secret is supplied for one test and gone after it', () async {
await DV.Test.withSecrets(<String, String>{'PAYSTACK_SECRET': 'sk_test_1'}, () {
expect(DV.Secrets.get('PAYSTACK_SECRET'), 'sk_test_1');
});
expect(DV.Secrets.has('PAYSTACK_SECRET'), isFalse);
});Copy code to clipboard
dartvel key generate
dartvel key status
dartvel key rotateCopy code to clipboard
The key encrypts what your app stores on the device. generate refuses to replace a key that exists.
It is held by the Secret Service on Linux, the Keychain on macOS and iOS, DPAPI on Windows and the Keystore on Android.
rotate records the old and new fingerprints, so you can tell which key wrote what.
Partial
Spec section: Secrets and Environments
Planned work and implementation limits
No Vault or cloud KMS adapter. A secrets manager feeds values in through DVSecrets.configure.
The build checks names written as literals only.
The Android Keystore and iOS Keychain paths have not been checked on real devices.
FSL-1.1-MIT licensed. Built with Dartvel.
Dartvel is made by
To the bottom