How do I load secrets from environment variables in EK9?
← Security and Sanitization · Ref: Q702
Use EnvVars.sensitiveGet() to load secret values as Sensitive type. This is the ONLY way to create a set Sensitive value in EK9.
BASIC PATTERN
env <- EnvVars() apiKey <- env.sensitiveGet("API_KEY") if apiKey? //Key is loaded and protected
GUARD PATTERN
Combine sensitiveGet() with guard expressions for clean handling:
if dbPassword <- env.sensitiveGet("DB_PASSWORD") connectDatabase(dbPassword) else stderr.println("DB_PASSWORD not configured")
GET vs SENSITIVEGET
env.get(name) Returns String, auto-sanitized against injection env.sensitiveGet(name) Returns Sensitive, auto-redacting wrapper
Use get() for configuration values (paths, URLs, feature flags).
Use sensitiveGet() for secrets (passwords, API keys, tokens).
MULTIPLE SECRETS
env <- EnvVars() dbHost <- env.get("DB_HOST") dbUser <- env.get("DB_USER") dbPass <- env.sensitiveGet("DB_PASSWORD")
Configuration values use get(), only the password uses sensitiveGet().
See Q701 for the Sensitive type overview. See Q703 for Privileged reveal(). See Q704 for compile-time secret detection. See Q271 for EnvVars get() patterns.
Example
defines module qa.security.sensitiveget defines function <?- Basic pattern: load a secret from an environment variable. -?> testBasicSensitiveGet() stdout <- Stdout() env <- EnvVars() apiKey <- env.sensitiveGet("API_KEY") if apiKey? stdout.println("API key loaded (redacted): " + apiKey) else stdout.println("API_KEY not set in environment") <?- Guard pattern: combine sensitiveGet with guard expression. -?> testGuardPattern() stdout <- Stdout() stderr <- Stderr() env <- EnvVars() if dbPassword <- env.sensitiveGet("DB_PASSWORD") stdout.println("Database password loaded") else stderr.println("DB_PASSWORD not configured") <?- Compare get() vs sensitiveGet() for different use cases. -?> testGetVsSensitiveGet() stdout <- Stdout() env <- EnvVars() //get() for configuration values if dbHost <- env.get("DB_HOST") stdout.println("DB host: " + dbHost) //sensitiveGet() for secrets dbPass <- env.sensitiveGet("DB_PASSWORD") if dbPass? //Auto-promotes to ***REDACTED*** stdout.println("DB password: " + dbPass) <?- Loading multiple secrets from environment. -?> testMultipleSecrets() stdout <- Stdout() env <- EnvVars() //Configuration uses get() region <- env.get("AWS_REGION") //Secrets use sensitiveGet() accessKey <- env.sensitiveGet("AWS_ACCESS_KEY_ID") secretKey <- env.sensitiveGet("AWS_SECRET_ACCESS_KEY") if region? stdout.println("Region: " + region) if accessKey? and secretKey? stdout.println("AWS credentials loaded") <?- Safe comparison of two secrets using constant-time equality. -?> testSecretComparison() stdout <- Stdout() env <- EnvVars() expected <- env.sensitiveGet("EXPECTED_TOKEN") provided <- env.sensitiveGet("PROVIDED_TOKEN") if expected? and provided? if expected == provided stdout.println("Tokens match") else stdout.println("Tokens do not match") defines program SensitiveGetDemo() stdout <- Stdout() stdout.println("sensitiveGet() demonstrations") testBasicSensitiveGet() testGuardPattern() testGetVsSensitiveGet() testMultipleSecrets() testSecretComparison()
Common mistakes
E11080 — AWS access keys must not be hardcoded. Load them from environment variables using sensitiveGet(). See ek9 -h E11080 for details.
Incorrect:
accessKey <- "AKIAIOSFODNN7EXAMPLE1"
Correct:
accessKey <- env.sensitiveGet("AWS_ACCESS_KEY_ID")
E11081 — GitHub personal access tokens must not be hardcoded. Load them from environment variables using sensitiveGet(). See ek9 -h E11081 for details.
Incorrect:
expected <- "ghp_ABCDEFabcdef1234567890abcdef12345678"
Correct:
expected <- env.sensitiveGet("EXPECTED_TOKEN")
E11083 — Database URLs with embedded passwords are detected at compile time. Store the connection string in an environment variable. See ek9 -h E11083 for details.
Incorrect:
dbPass <- "postgres://admin:s3cret@db.example.com/prod"
Correct:
dbPass <- env.sensitiveGet("DB_PASSWORD")
E11084 — JWT tokens must not be hardcoded in source code. Generate tokens at runtime or load from environment variables. See ek9 -h E11084 for details.
Incorrect:
provided <- "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.dozjgNryP4J3jVmNHl0w5N_XgL0n3I9PlFUP0THsR8U"
Correct:
provided <- env.sensitiveGet("PROVIDED_TOKEN")
Other ways to ask this
- What is sensitiveGet() in EK9?
- How do I use EnvVars to load credentials safely?
- What is the difference between get() and sensitiveGet()?
Coming from another language?
Java: System.getenv() returns raw String with no protection class. Secrets are indistinguishable from configuration. Python: os.environ returns raw strings. Go: os.Getenv returns raw string. Rust: std::env::var returns raw string. All these allow secrets to be logged, serialized, or leaked. EK9: sensitiveGet() returns Sensitive type that auto-redacts on any string conversion.
Keywords: runtime, connect, safe, secret, database, envvars, credential, service, url, guard, load, environment, token, sensitiveGet, password, username, configuration