Configuration
Before using the URA EFRIS System-to-System SDKs, you must configure your environment variables and SDK bootstrap settings. This ensures proper authentication, key exchange, encryption, and API usage.
- PHP
- JavaScript / TypeScript
- Python
PHP SDK Configuration
Load environment variables and bootstrap the SDK:
use UraEfrisSdk\Client;
use UraEfrisSdk\KeyClient;
use Dotenv\Dotenv;
// Load env variables using dotenv if needed
$dotenv = Dotenv::createImmutable(__DIR__);
$dotenv->load();
// SDK Config
$config = [
'env' => getenv('EFRIS_ENV') ?: 'sbx',
'tin' => getenv('EFRIS_TIN'),
'device_no' => getenv('EFRIS_DEVICE_NO'),
'brn' => getenv('EFRIS_BRN') ?: '',
'taxpayer_id' => getenv('EFRIS_TAXPAYER_ID') ?: '1',
'pfx_path' => getenv('EFRIS_PFX_PATH'),
'pfx_password' => getenv('EFRIS_PFX_PASSWORD'),
'http' => [
'timeout' => (int) (getenv('EFRIS_HTTP_TIMEOUT') ?: 120)
]
];
// Initialize KeyClient (handles RSA/AES encryption)
$keyClient = new KeyClient(
pfxPath: $config['pfx_path'],
password: $config['pfx_password'],
tin: $config['tin'],
deviceNo: $config['device_no'],
brn: $config['brn'],
sandbox: $config['env'] === 'sbx',
timeout: $config['http']['timeout'],
taxpayerId: $config['taxpayer_id']
);
// Initialize main Client
$client = new Client(config: $config, keyClient: $keyClient);
// Optional: Run initialization flow on first run
// $client->clientInit(); // T102 - Get RSA keys
// $client->signIn(); // T103 - Authenticate & get metadata
// $client->getSymmetricKey(); // T104 - Get AES key for subsequent calls
JavaScript / TypeScript SDK Configuration
Load environment variables and bootstrap the SDK:
import { Client, KeyClient } from 'ura-efris-sdk';
import { loadConfigFromEnv, validateConfig } from 'ura-efris-sdk/config';
// Load configuration from environment variables
const config = loadConfigFromEnv('EFRIS');
// Validate required fields
try {
validateConfig(config);
} catch (error) {
console.error(`❌ Configuration error: ${(error as Error).message}`);
process.exit(1);
}
// Initialize KeyClient (handles RSA/AES encryption)
const keyClient = new KeyClient(
config.pfx_path,
config.pfx_password,
config.tin,
config.device_no,
config.brn ?? '',
config.env === 'sbx',
config.http?.timeout ?? 120,
config.taxpayer_id ?? '1'
);
// Initialize main Client
const client = new Client(config, keyClient);
// Optional: Run initialization flow explicitly on first run
// await client.getServerTime(); // T101 - Sync time
// await client.clientInit(); // T102 - Get RSA keys
// await client.signIn(); // T103 - Authenticate
// await client.getSymmetricKey(); // T104 - Get AES key
Python SDK Configuration
Load environment variables and bootstrap the SDK:
import os
from ura_efris_sdk import (
Client,
KeyClient,
load_config_from_env,
validate_config
)
from ura_efris_sdk.exceptions import APIException, ValidationException
from dotenv import load_dotenv
# Load .env file if present
load_dotenv()
# Load configuration from environment variables
config = load_config_from_env(prefix="EFRIS")
# Validate required fields
try:
validate_config(config)
except ValueError as e:
print(f"❌ Configuration error: {e}")
exit(1)
# Handle password (may be bytes from environment)
password = config["pfx_password"]
if isinstance(password, bytes):
password = password.decode()
# Initialize KeyClient (handles RSA/AES encryption)
key_client = KeyClient(
pfx_path=config["pfx_path"],
password=password,
tin=config["tin"],
device_no=config["device_no"],
brn=config.get("brn", ""),
sandbox=config["env"] == "sbx",
timeout=config.get("http", {}).get("timeout", 120),
taxpayer_id=config.get("taxpayer_id", "1")
)
# Initialize main Client
client = Client(config=config, key_client=key_client)
# Optional: Run initialization flow explicitly on first run
# client.get_server_time() # T101 - Sync time
# client.client_init() # T102 - Get RSA keys
# client.sign_in() # T103 - Authenticate
# client.get_symmetric_key() # T104 - Get AES key
Environment Variables Reference
| Variable | Description | Example | Required |
|---|---|---|---|
EFRIS_ENV | Environment: sbx or prod | sbx | ✅ |
EFRIS_TIN | Taxpayer Identification Number | 1000029771 | ✅ |
EFRIS_DEVICE_NO | Device Serial Number (DSN) | TCS9e0df01728335239 | ✅ |
EFRIS_BRN | Business Registration Number | BRN123456 | ❌ |
EFRIS_TAXPAYER_ID | Taxpayer internal ID (usually 1) | 1 | ❌ |
EFRIS_PFX_PATH | Path to .pfx certificate file | /secure/certs/ura.pfx | ✅ |
EFRIS_PFX_PASSWORD | Password for the PFX certificate | •••••••• | ✅ |
EFRIS_HTTP_TIMEOUT | HTTP request timeout in seconds | 120 | ❌ |
EFRIS_LOG_LEVEL | Logging level: debug | info | warn | error | info | ❌ |
Sample .env File
# Environment
EFRIS_ENV=sbx
# Taxpayer Credentials
EFRIS_TIN=1000029771
EFRIS_DEVICE_NO=TCS9e0df01728335239
EFRIS_BRN=
EFRIS_TAXPAYER_ID=1
# Certificate
EFRIS_PFX_PATH=/path/to/secure/ura.pfx
EFRIS_PFX_PASSWORD=your_secure_password
# Network
EFRIS_HTTP_TIMEOUT=120
# Logging (JS/TS only)
EFRIS_LOG_LEVEL=info
Step-by-Step Breakdown
| Step | Interface | Purpose | Key Outputs |
|---|---|---|---|
| 1 | T101: Get Server Time | Synchronize client clock with URA server | currentTime (dd/MM/yyyy HH:mm:ss) |
| 2 | T102: Client Initialization | Exchange RSA keys with URA | clientPriKey, serverPubKey, keyTable |
| 3 | T103: Sign In | Authenticate taxpayer & retrieve metadata | Taxpayer info, branch list, feature flags, dictionaryVersion |
| 4 | T104: Get Symmetric Key | Obtain AES key for payload encryption | passowrdDes, sign |
💡 Tip: The SDK handles this flow automatically on the first API call. You only need to run it manually if you want to pre-warm keys or handle initialization errors explicitly.
Certificate & Key Management
PFX Certificate Requirements
| Requirement | Specification |
|---|---|
| Format | PKCS#12 (.pfx or .p12) |
| Key Size | RSA 2048-bit minimum |
| Contents | Must contain both private key and public certificate |
| Protection | Password-protected (use strong passwords) |
| Validity | Must not be expired; renew before expiration |
Key Rotation Procedure
- Generate new PFX certificate via URA portal or contact URA support
- Update
EFRIS_PFX_PATHandEFRIS_PFX_PASSWORDin your environment - Restart your application to reload credentials
- Re-run initialization flow (
T102→T103→T104) - Verify API calls succeed with new credentials
Security Best Practices
| Practice | Implementation |
|---|---|
| 🔐 Protect certificates | Store .pfx files in encrypted storage or HSM; never in source control |
| 🔑 Restrict file permissions | chmod 600 /path/to/cert.pfx; use OS-level access controls |
| 🚫 Avoid logging sensitive data | Mask content, signature, clientPriKey, passowrdDes in logs |
| 🔄 Rotate credentials regularly | Update PFX certificates and device credentials on staff/system changes |
| 🧪 Test in sandbox first | Always validate initialization and API flows in sbx before prod |
| 📋 Maintain audit logs | Log all API requests/responses with masked sensitive fields for compliance |
| ⏰ Monitor clock drift | Alert if time synchronization exceeds ±5 minutes to prevent ReturnCode: 28 |
| 🛡️ Validate inputs early | Use SDK's built-in validation to catch errors before network calls |
Troubleshooting Common Configuration Issues
| Symptom | Likely Cause | Solution |
|---|---|---|
ReturnCode: 28 | Clock drift >10 minutes | Sync system time; call T101 before initialization |
ReturnCode: 400 | Invalid or missing deviceNo | Verify EFRIS_DEVICE_NO matches URA registration |
ReturnCode: 401 | Missing or expired device keys | Re-run T102: Client Initialization |
ReturnCode: 100 | Invalid or unregistered tin | Confirm TIN is active in URA system |
EncryptionException | Invalid PFX password or corrupt certificate | Verify EFRIS_PFX_PASSWORD; regenerate certificate if needed |
ValidationException | Missing required fields in payload | Use SDK methods; avoid manual JSON construction |
Connection timeout | Network/firewall blocking URA endpoints | Allow outbound HTTPS to efrisws.ura.go.ug and efristest.ura.go.ug |