Configuration
info
AquaGen API fetches all secrets from Azure Key Vault at startup. Key Vault credentials are hardcoded in app/enum/env.py — no environment variable setup is required to run the app.
How It Works
FLASK_ENV → selects vault URL → SecretManager authenticates → Config class pulls all secrets
Startup secret loading
FLASK_ENV(devorprod) selects which Key Vault to connect toSecretManagerinapp/services/secret_vault_service.pyauthenticates using theClientSecretCredentialfromapp/enum/env.pyConfigclass inapp/config.pycallssmi.get(SecretName.XYZ)for each secret at startup
Key Vaults
| Environment | Vault URL |
|---|---|
Production (prod) | https://aquagen.vault.azure.net/ |
Development (dev) | https://aquagendev.vault.azure.net/ |
Environment Variables
Only a small number of env vars are read directly from the environment (not Key Vault):
| Variable | Description | Default |
|---|---|---|
FLASK_ENV | Selects dev or prod Key Vault | Required |
APPLICATIONINSIGHTS_CONNECTION_STRING | App Insights connection (fallback if Key Vault secret not set) | Optional |
TEST_OTP_ENABLED | Enable test OTP bypass (true/false) | true in dev |
TEST_OTP | OTP value used when test mode is on | 123456 |
ALLOWED_FRAME_ANCESTORS | CSP frame-ancestors header value | Preset list of known frontend origins |
To run locally:
export FLASK_ENV=dev
export FLASK_DEBUG=1
flask run --host localhost --port 5001
Azure Key Vault Secrets
All other configuration is pulled from Key Vault. Secret names follow a hyphen-separated convention:
Database
| Secret Name | Description |
|---|---|
COSMOSDBENDPOINT | Azure Cosmos DB endpoint URL |
COSMOSDBKEY | Cosmos DB primary access key |
Authentication
| Secret Name | Description |
|---|---|
SECRET-KEY | Flask JWT secret key |
AZURE-AD-APP-ID | Azure AD application (client) ID |
AZURE-AD-ISSUER | Azure AD token issuer URL |
AZURE-AD-JWKS-URI | Azure AD JSON Web Key Set URI |
GOOGLE-CLIENT-ID | Google OAuth client ID |
GOOGLE-CLIENT-SECRET | Google OAuth client secret |
ADMIN-ACCOUNT-TID | Admin Azure AD tenant ID |
ADMIN-LOGIN-TYPE | Admin login method |
INTERNAL-INDUSTRY-ID | Internal/system industry ID |
Notifications
| Secret Name | Description |
|---|---|
FIREBASE-CREDENTIALS | Firebase service account JSON |
FIREBASE-STORAGE-BUCKET | Firebase storage bucket name |
SMS-API-ENDPOINT | SMS gateway API URL |
SMS-USER-ID | SMS gateway user ID |
SMS-PASSWORD | SMS gateway password |
MSG-TYPE | SMS message type |
SMS-VERSION | SMS API version |
SMS-FORMAT | SMS response format |
Azure Services
| Secret Name | Description |
|---|---|
APPLICATION-INSIGHTS | App Insights connection string |
IOTHUB-CONNECTION-STRING | Azure IoT Hub connection string |
WEBPUB-ENDPOINT | Azure Web PubSub endpoint |
HUB-NAME | Web PubSub hub name |
WEBSOCKET-ENDPOINT | WebSocket endpoint URL |
WEBSOCKET-HUB-NAME | WebSocket hub name |
EVENTHUB-CONNECTION-STRING | Azure Event Hub connection string |
EVENTHUB-NAME | Event Hub name |
Analytics & AI
| Secret Name | Description |
|---|---|
AQUA-GPT-API-KEY | AquaGPT API key |
AQUA-GPT-ASSISTANT-ID | AquaGPT assistant ID |
AQUA-GPT-MODEL | AquaGPT model name |
EARTH-ENGINE-SERVICE-ACCOUNT | Google Earth Engine service account JSON |
SecretManager Usage Pattern
from app.services.secret_vault_service import smi
from app.enum.secret_key_type import SecretName
from app.enum.secret_key_format_type import SecretKeyFormatType
# String secret
SECRET_KEY = smi.get(SecretName.SECRET_KEY)
# JSON dict secret
FIREBASE_CREDENTIALS = smi.get(SecretName.FIREBASE_CREDENTIALS, SecretKeyFormatType.dict)
# Integer secret
SOME_INT = smi.get(SecretName.SOME_INT, SecretKeyFormatType.int)
SecretKeyFormatType options: dict (JSON parse), int, float, default is string.
JWT Configuration
Set in app/__init__.py:
app.config["JWT_TOKEN_LOCATION"] = ["headers", "query_string"]
app.config["JWT_SECRET_KEY"] = Config.SECRET_KEY
app.config["JWT_ACCESS_TOKEN_EXPIRES"] = timedelta(hours=4)
app.config["JWT_REFRESH_TOKEN_EXPIRES"] = timedelta(days=14)
note
- Access tokens expire after 4 hours
- Refresh tokens expire after 14 days
- Token accepted from
Authorizationheader orjwtquery string parameter
CORS
CORS is open to all origins:
CORS(app, resources={r'/*': {"origins": '*'}})
tip
The ALLOWED_FRAME_ANCESTORS env var controls the CSP frame-ancestors directive, which restricts which origins can embed the app in an iframe. Defaults to the known set of AquaGen frontend domains.