12 KiB
Portal Server
A dedicated HTTP server for the portal application that provides KYC verification endpoints and Stripe payment processing.
Features
- KYC Verification: Integration with Identify API for identity verification
- Create verification sessions
- Handle verification result webhooks
- Check verification status
- Payment Processing: Stripe integration for company and resident registrations
- Create payment intents for companies and residents
- Handle Stripe webhooks
- Payment success/failure redirects
- Security Features: Production-ready security configurations
- API Key Authentication: Configurable API key authentication for protected endpoints
- Webhook Signature Verification: HMAC-SHA256 verification for Stripe and Identify webhooks
- Feature-based CORS policies (dev vs prod)
- Origin restrictions for production deployments
- Configurable: Command-line flags and environment variables
- Static File Serving: Optional static file serving
Quick Start
Getting 401 errors? See the detailed SETUP.md guide for step-by-step instructions.
Quick Start
1. Set Up Environment File
The portal-server requires API keys for authentication. Create a .env
file to get started quickly:
# Copy the example file
cp .env.example .env
# Edit the .env file with your actual keys
nano .env
2. Configure Required Keys
Edit your .env
file with these required values:
# Stripe Configuration (Required)
STRIPE_SECRET_KEY=sk_test_your_actual_stripe_secret_key
STRIPE_PUBLISHABLE_KEY=pk_test_your_actual_stripe_publishable_key
# Identify KYC Configuration (Required)
IDENTIFY_API_KEY=your_actual_identify_api_key
# API Keys for Authentication (Required to avoid 401 errors)
API_KEYS=dev_key_123,another_key_456
3. Run the Server
# Run with .env file (recommended)
cargo run -- --from-env --verbose
# Or specify custom .env file location
cargo run -- --from-env --env-file /path/to/your/.env --verbose
4. Test API Access
All protected endpoints require the x-api-key
header:
# Test with API key (replace dev_key_123 with your actual key)
curl -X GET http://localhost:3001/api/health \
-H "x-api-key: dev_key_123"
# Without API key = 401 Unauthorized
curl -X GET http://localhost:3001/api/health
5. Common Issues
Getting 401 Unauthorized?
- ✅ Make sure
API_KEYS
is set in your.env
file - ✅ Include
x-api-key
header in all API requests - ✅ Use one of the keys from your
API_KEYS
list
Server won't start?
- ✅ Check that all required environment variables are set
- ✅ Verify your Stripe and Identify API keys are valid
- ✅ Make sure the
.env
file is in the correct location
.env File Configuration
The server supports flexible .env file loading:
Default Locations (checked in order)
.env
(current directory)portal-server/.env
(portal-server subdirectory)
Custom .env File Path
# Use custom .env file location
cargo run -- --from-env --env-file /path/to/custom/.env
Environment Variables Priority
- Command line arguments (highest priority)
- .env file values
- System environment variables
- Default values (lowest priority)
API Endpoints
KYC Verification
POST /api/kyc/create-verification-session
- Create a new KYC verification sessionPOST /api/kyc/verification-result-webhook
- Handle verification results from IdentifyPOST /api/kyc/is-verified
- Check if a user is verified
Payment Processing
POST /api/company/create-payment-intent
- Create payment intent for company registrationPOST /api/resident/create-payment-intent
- Create payment intent for resident registrationGET /api/company/payment-success
- Payment success redirectGET /api/company/payment-failure
- Payment failure redirectPOST /api/webhooks/stripe
- Handle Stripe webhooks
Health Check
GET /api/health
- Server health check
Usage
Command Line
# Run with command line arguments
./portal-server \
--host 0.0.0.0 \
--port 3001 \
--stripe-secret-key sk_test_... \
--stripe-publishable-key pk_test_... \
--identify-api-key identify_... \
--api-keys dev_key_123,prod_key_456 \
--static-dir ./static
# Run with .env file (recommended)
./portal-server --from-env
# Run with custom .env file location
./portal-server --from-env --env-file /path/to/custom/.env
# Show help
./portal-server --help
Environment Variables
Create a .env
file or set these environment variables:
# Server configuration
HOST=127.0.0.1
PORT=3001
# Stripe configuration
STRIPE_SECRET_KEY=sk_test_...
STRIPE_PUBLISHABLE_KEY=pk_test_...
STRIPE_WEBHOOK_SECRET=whsec_...
# Identify KYC configuration
IDENTIFY_API_KEY=identify_...
IDENTIFY_WEBHOOK_SECRET=your_identify_webhook_secret
IDENTIFY_API_URL=https://api.identify.com
# Security configuration
API_KEYS=api_key_1,api_key_2,api_key_3
# CORS configuration (use specific domains in production)
CORS_ORIGINS=https://app.freezone.com,https://portal.freezone.com
Library Usage
use portal_server::{PortalServerBuilder, ServerConfig};
#[tokio::main]
async fn main() -> anyhow::Result<()> {
// Load configuration
let config = ServerConfig::from_env()?;
// Build and run server
let server = PortalServerBuilder::new(config)
.with_static_dir("./static")
.build()
.await?;
server.run().await?;
Ok(())
}
Configuration
Command Line Options
--host
- Server host address (default: 127.0.0.1)--port
- Server port (default: 3001)--stripe-secret-key
- Stripe secret key (required)--stripe-publishable-key
- Stripe publishable key (required)--stripe-webhook-secret
- Stripe webhook secret (optional)--identify-api-key
- Identify API key for KYC (required)--identify-webhook-secret
- Identify webhook secret for signature verification (optional)--api-keys
- API keys for authentication, comma-separated (optional)--identify-api-url
- Identify API URL (default: https://api.identify.com)--cors-origins
- CORS allowed origins, comma-separated (default: *)--static-dir
- Directory to serve static files from (optional)--from-env
- Load configuration from environment variables--env-file
- Path to .env file (defaults to .env in current directory)--verbose
- Enable verbose logging
Required Environment Variables
When using --from-env
flag, these environment variables are required:
STRIPE_SECRET_KEY
- Your Stripe secret keySTRIPE_PUBLISHABLE_KEY
- Your Stripe publishable keyIDENTIFY_API_KEY
- Your Identify API key for KYC verification
Security & Build Modes
The server supports two build modes with different security configurations:
Development Mode (Default)
- CORS: Permissive (allows all origins)
- Purpose: Local development and testing
- Build:
cargo build
orcargo build --features dev
Production Mode
- CORS: Restricted to specified origins only
- Purpose: Production deployments
- Build:
cargo build --features prod --no-default-features
CORS Configuration
Development Mode
# Allows all origins for easy local development
cargo run -- --cors-origins "*"
Production Mode
# Restrict to your app domains only
cargo build --features prod --no-default-features
./target/release/portal-server --cors-origins "https://app.freezone.com,https://portal.freezone.com"
Development
Building
# Development build (default)
cargo build --release
# Production build with security restrictions
cargo build --release --features prod --no-default-features
Running
# Development mode (permissive CORS)
cargo run -- --verbose
# Development with environment file
cargo run -- --from-env --verbose
# Production mode (restricted CORS)
cargo build --features prod --no-default-features
./target/release/portal-server --from-env --cors-origins "https://yourdomain.com"
Testing
cargo test
Security Recommendations
Production Deployment
For production deployments, consider implementing additional security measures beyond CORS:
- API Key Authentication: Add API key validation for sensitive endpoints
- Rate Limiting: Implement rate limiting to prevent abuse
- Request Size Limits: Set maximum request body sizes
- HTTPS Only: Always use HTTPS in production
- Firewall Rules: Restrict server access at the network level
- Environment Variables: Never expose API keys in logs or error messages
Current Security Features
✅ API Key Authentication: All protected endpoints require valid API key in x-api-key
header
✅ Webhook Signature Verification: HMAC-SHA256 verification for both Stripe and Identify webhooks
✅ CORS Origin Restrictions: Production mode restricts origins to specified domains
✅ Input Validation: All endpoints validate request data
✅ Feature-based Configuration: Separate dev/prod security policies
✅ Constant-time Comparison: Secure signature verification to prevent timing attacks
API Key Authentication
Protected endpoints require a valid API key in the x-api-key
header:
# Example API call with authentication
curl -X POST http://localhost:3001/api/kyc/create-verification-session \
-H "Content-Type: application/json" \
-H "x-api-key: your_api_key_here" \
-d '{"user_id": "user123", "email": "user@example.com"}'
Protected Endpoints:
- All KYC endpoints (except webhooks)
- All payment endpoints (except webhooks and redirects)
- Legacy endpoints
Unprotected Endpoints:
- Health check (
/api/health
) - Webhook endpoints (use signature verification instead)
Additional Security (Recommended)
Consider implementing these additional security measures:
// Example: Rate limiting (not implemented)
async fn rate_limit(req: Request<Body>, next: Next<Body>) -> Response {
// Check request rate per IP
// Return 429 if exceeded
}
API Examples
Create KYC Verification Session
curl -X POST http://localhost:3001/api/kyc/create-verification-session \
-H "Content-Type: application/json" \
-H "x-api-key: your_api_key_here" \
-d '{
"user_id": "user123",
"email": "user@example.com",
"return_url": "https://yourapp.com/verification-complete",
"webhook_url": "https://yourapp.com/webhook"
}'
Check Verification Status
curl -X POST http://localhost:3001/api/kyc/is-verified \
-H "Content-Type: application/json" \
-H "x-api-key: your_api_key_here" \
-d '{
"user_id": "user123"
}'
Create Payment Intent
curl -X POST http://localhost:3001/api/company/create-payment-intent \
-H "Content-Type: application/json" \
-H "x-api-key: your_api_key_here" \
-d '{
"company_name": "Example Corp",
"company_type": "Startup FZC",
"company_email": "contact@example.com",
"payment_plan": "monthly",
"agreements": ["terms", "privacy"],
"final_agreement": true
}'
Architecture
The server is built using:
- Axum - Web framework
- Tokio - Async runtime
- Reqwest - HTTP client for external APIs
- Serde - JSON serialization
- Tracing - Logging and observability
- Clap - Command-line argument parsing
The codebase is organized into:
src/lib.rs
- Library exportssrc/config.rs
- Configuration managementsrc/models.rs
- Data models and typessrc/services.rs
- External API integrations (Stripe, Identify)src/handlers.rs
- HTTP request handlerssrc/server.rs
- Server builder and configurationcmd/main.rs
- Command-line interface
License
This project is part of the FreeZone platform.