#
Security Architecture
The Valu API ecosystem implements multiple layers of security to protect user data, financial transactions, and identity information across all integrated services.
#
Mobile App Authentication
#
Seed-Based Authentication Flow
sequenceDiagram
participant User
participant App as Mobile App
participant API as Valu API
participant DB as Database
User->>App: Enter/Generate Seed
App->>App: Generate Bearer Token from Seed
Note over App: bearerFromSeed(seed)
App->>API: POST /sessions/auth/key
Note over App,API: {secretKey, network}
API->>DB: Check if secret exists
alt Secret not found
API->>DB: Create new user
DB-->>API: New user & API key
else Secret exists
DB-->>API: Existing user & API key
end
API-->>App: {authenticatedAs, apiKey, success}
App->>App: Store credentials & setup interceptors
#
Bearer Token Generation
The mobile app generates cryptographically secure bearer tokens from the user's seed:
static bearerFromSeed = async (seed) => {
var ripemd160 = crypto.createHash("ripemd160");
var sha256 = crypto.createHash("sha256");
const VALU_SERVICE_CANONICAL = Buffer.from(VALU_SERVICE_ID, "utf8");
const sha256Hash = sha256
.update(await mnemonicToSeed(seed))
.update(VALU_SERVICE_CANONICAL)
.digest();
return ripemd160.update(sha256Hash).digest().toString("hex");
};
Security Features:
- Uses RIPEMD-160 and SHA-256 hashing
- Incorporates service-specific canonical identifier
- Derives from BIP39 mnemonic seed
- Generates deterministic but unique tokens per service
#
Request Signing & Authentication
#
API Request Security
flowchart TD
Request[API Request] --> Method{HTTP Method}
Method -->|GET| GetFlow[Sign URL String]
Method -->|POST/PUT| PostFlow[Sign URL + JSON Body]
GetFlow --> Sign1[Generate Signature]
PostFlow --> Sign2[Generate Signature]
Sign1 --> Headers[Add Security Headers]
Sign2 --> Headers
Headers --> Send[Send Signed Request]
Send --> Verify[Valu API Verifies Signature]
Verify --> Process[Process Request]
#
Request Interceptor Implementation
authenticate(valuToken, apiKey) {
this.authInterceptor = this.service.interceptors.request.use(
(config) => {
config.url = config.url.includes("timestamp")
? config.url
: config.url + `?timestamp=${Date.now()}`;
if (config.method === "get") {
config.headers["x-api-signature"] = ValuService.signUrlString(
axios.getUri(config),
valuToken
);
} else {
let uri = axios.getUri(config);
if (uri.substr(0, 4) !== "http") {
uri = config.baseURL.replace(/\/+$/, "") + uri;
}
config.headers["x-api-signature"] = ValuService.signUrlString(
config.data == null ? uri : uri + JSON.stringify(config.data),
valuToken
);
}
config.headers["x-payload-digest-alg"] = "sha256";
config.headers["x-api-key"] = apiKey;
return config;
}
);
}
Security Headers:
x-api-signature: HMAC signature of requestx-payload-digest-alg: Hashing algorithm identifierx-api-key: User-specific API keytimestamp: Prevents replay attacks
#
External Service Security
#
Sumsub KYC Integration
sequenceDiagram
participant VA as Valu API
participant SB as Sumsub API
VA->>VA: Generate timestamp
VA->>VA: Create HMAC signature
Note over VA: timestamp + method + url + body
VA->>SB: Request with security headers
Note over VA,SB: X-App-Token, X-App-Access-Sig, X-App-Access-Ts
SB->>SB: Verify signature
SB-->>VA: Authenticated responseImplementation:
const getSigBuilder = (apiToken, secretKey) => config => {
const timestamp = Math.floor(Date.now() / 1000)
const signature = crypto.createHmac('sha256', secretKey)
signature.update(`${timestamp}${_.toUpper(config.method)}${config.url}`)
if (config.data instanceof FormData) {
signature.update(config.data.getBuffer())
} else if (config.data) {
signature.update(JSON.stringify(config.data))
}
config.headers['X-App-Token'] = apiToken
config.headers['X-App-Access-Sig'] = signature.digest('hex')
config.headers['X-App-Access-Ts'] = timestamp
return config
}
#
Paybis Payment Security
sequenceDiagram
participant VA as Valu API
participant PB as Paybis API
VA->>VA: Hash request body (SHA-512)
VA->>VA: Sign hash with RSA private key
Note over VA: RSA-PSS-SALTLEN-DIGEST padding
VA->>PB: Request with signature header
Note over VA,PB: X-Request-Signature (Base64)
PB->>PB: Verify RSA signature
PB-->>VA: Authenticated responseRSA Signature Implementation:
const getSigBuilder = (privateKey, secretKey) => config => {
if (!config.data) return config
const hash = crypto.createHash('sha512');
const hashedData = hash.update(JSON.stringify(config.data), 'utf-8').digest('hex');
const signature = crypto.sign("sha512", Buffer.from(hashedData), {
key: privateKey,
padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
saltLength: crypto.constants.RSA_PSS_SALTLEN_DIGEST,
})
config.headers['X-Request-Signature'] = signature.toString('base64')
return config
}
#
Stripe API Security
flowchart LR
VA[Valu API] -->|Bearer Token| Stripe[Stripe API]
Stripe -->|HTTPS/TLS| Response[Encrypted Response]
subgraph "Security Layer"
Bearer[Bearer Token Authentication]
TLS[TLS 1.3 Encryption]
Webhook[Webhook Signatures]
endBearer Token Authentication:
const response = await fetch(url, {
method: 'GET',
headers: {
'Authorization': `Bearer ${process.env.STRIPE_SK}`,
'Content-Type': 'application/json'
}
});
#
Blockchain Security
#
Verus Blockchain Connection
sequenceDiagram
participant VA as Valu API
participant VD as Verus Daemon
VA->>VD: RPC Call with credentials
Note over VA,VD: HTTP Basic Auth
VD->>VD: Validate credentials
VD-->>VA: Blockchain responseConfiguration:
// Environment variables for Verus daemon connection
REMOTE_PASS="pass5ed21ad207f6a373d390a"
REMOTE_PROTOCOL="http"
REMOTE_HOST="18.212.94.218"
REMOTE_PORT="18843"
REMOTE_USER="user15"
#
Polygon Blockchain Security
flowchart TD
Wallet[Wallet Instance] --> Provider[JSON RPC Provider]
Provider --> Network[Polygon Amoy Network]
subgraph "Security Measures"
PrivKey[Private Key Encryption]
TxSign[Transaction Signing]
AddressVal[Address Validation]
end
Wallet --> PrivKey
Wallet --> TxSign
Network --> AddressValSecure Transaction Handling:
const provider = new JsonRpcProvider("https://rpc-amoy.polygon.technology/");
const wallet = new Wallet(process.env.POLYGON_AMOY_PRIVATE_KEY, provider);
async function payUSDC(toAddress, amount) {
try {
if (!isAddress(toAddress)) {
throw new Error("Invalid recipient address");
}
const usdcContract = new Contract(usdcContractAddress, usdcAbi, wallet);
const amountInSmallestUnit = parseUnits(amount, 6);
const transactionResponse = await usdcContract.transfer(toAddress, amountInSmallestUnit);
await transactionResponse.wait(); // Wait for confirmation
return transactionResponse.hash;
} catch (error) {
console.error("Error sending USDC payment:", error);
throw error;
}
}
#
Database Security
#
User Data Protection
erDiagram
USERS {
uuid id PK
string status
string password "Hashed seed"
uuid api_key
string network
timestamp created_at
timestamp updated_at
}
SESSIONS {
uuid session_id PK
uuid user_id FK
string bearer_token "Hashed"
timestamp expires_at
boolean active
}
TRANSACTIONS {
uuid tx_id PK
uuid user_id FK
string type
decimal amount
string status
json metadata "Encrypted"
}Database Connection Security:
// Environment variables for database
DB_USER='admin'
DB_PASS='encrypted_password'
DB_NAME='valu_db'
DB_HOST="localhost"
DB_PORT="3306"
#
Security Best Practices
#
1. Cryptographic Standards
- SHA-256 and RIPEMD-160 for hashing
- RSA-PSS for digital signatures
- HMAC-SHA256 for request authentication
- TLS 1.3 for transport encryption
#
2. Key Management
flowchart TD
Seed[User Seed] --> Derive[Key Derivation]
Derive --> Bearer[Bearer Token]
Derive --> Wallet[Wallet Keys]
Env[Environment Variables] --> API[API Keys]
Env --> DB[Database Credentials]
HSM[Hardware Security Module] --> Critical[Critical Keys]
classDef secure fill:#e8f5e8
class HSM,Critical secure
#
3. Access Control
- Role-based permissions
- API rate limiting
- Session timeout management
- Multi-factor authentication for admin access
#
4. Audit & Monitoring
- Request/response logging
- Failed authentication tracking
- Anomaly detection
- Real-time security alerts
#
5. Data Protection
- Sensitive data encryption at rest
- PII data anonymization
- GDPR compliance measures
- Regular security audits