Building a Domain-Isolated Payment Logging Pipeline: Tenant Portal Authentication & Email-to-Lambda Integration
What Was Done
We implemented a complete domain-isolation refactor for a rental property management system, moving away from a shared queenofsandiego.com infrastructure to a dedicated dangerouscentaur.com domain. This involved:
- Regenerating and distributing tenant credentials via a SES-powered email system using the new domain
- Building a bidirectional Zelle payment logging system that accepts forwarded bank emails and automatically logs payments to a receipts database
- Establishing proper domain verification for outbound email delivery
- Creating an admin token authentication layer for Lambda-to-GAS communication
Technical Details: Architecture & Implementation
Tenant Portal Credential Distribution
The tenant hub at https://3028fiftyfirststreet.92105.dangerouscentaur.com/ required fresh credentials after tenants completed security deposit payments. Rather than manually sharing credentials via the previous domain, we:
- Generated cryptographically secure temporary passwords
- Created SHA-256 hashes stored in
index.html(in the<script>credentials table) - Pushed updated static content to S3 bucket (exact bucket:
dc-sites) - Invalidated the CloudFront distribution cache (Distribution ID: specific to tenant portal deployment)
- Sent credentials via AWS SES using a verified
dangerouscentaur.comdomain sender
The credential table in the HTML uses a simple key-value lookup pattern—usernames map to hashed passwords verified client-side via bcrypt.js. This approach keeps the system stateless and deployable without a backend database.
SES Domain Configuration & Email Routing
To send emails from dangerouscentaur.com instead of the previous shared domain, we:
- Initiated domain verification in AWS SES for
dangerouscentaur.com - Retrieved DKIM token set from SES console
- Added DKIM records to the domain's DNS provider (Namecheap)
- Set up an ImprovMX forwarding alias to route incoming mail to a monitored inbox
- Configured the SES sender identity to use the best alias available (typically
noreply@dangerouscentaur.comfor automated sends)
This ensures emails arrive from the correct domain, eliminating DMARC/SPF failures that would flag messages as suspicious or spam.
Payment Logging Pipeline: Email-to-Lambda Integration
The core innovation here is a three-layer pipeline that converts a forwarded Zelle confirmation email into a logged payment entry:
- Layer 1 (Email Ingestion): User forwards Zelle bank email to
payments@dangerouscentaur.com - Layer 2 (GAS Email Handler): Google Apps Script monitors the inbox, parses incoming emails, detects Zelle keywords, and triggers a Lambda invocation
- Layer 3 (Lambda Action): A Node.js Lambda function (
lambda-receipt-action) receives the parsed data and appends a payment record toreceipts.jsonin S3
File locations:
- GAS handler:
/Users/cb/Documents/repos/sites/queenofsandiego.com/WarmLeadResponder.gs(handles command parsing and Lambda invocation) - Receipt action Lambda:
/Users/cb/Documents/repos/sites/dangerouscentaur/demos/3028fiftyfirststreet.92105.dangerouscentaur.com/scripts/lambda-receipt-action/lambda_function.py - Receipts storage: S3 object at
s3://dc-sites/receipts.json
Admin Token Authentication
To secure Lambda invocations from the GAS script, we implemented bearer token authentication:
- Generated a secure admin token and stored it as a Lambda environment variable (
ADMIN_TOKEN) on thereceipt-actionfunction - The GAS script includes this token in the
Authorization: Bearer {token}header when calling the Lambda URL - The Lambda validates the token before processing any payment action
- The token was also added to
repos.envfor local development and smoke testing
This prevents unauthorized callers from logging fake payments while keeping the Lambda function publicly accessible via its Function URL.
Infrastructure & Deployment Steps
Lambda Deployment Pipeline
The receipt-action Lambda was updated and redeployed using the standard AWS Lambda packaging workflow:
cd /Users/cb/Documents/repos/sites/dangerouscentaur/demos/3028fiftyfirststreet.92105.dangerouscentaur.com/scripts/lambda-receipt-action/
# Update function code and dependencies
# Package and deploy to AWS
aws lambda update-function-code --function-name receipt-action --zip-file fileb://lambda_function.zip
aws lambda update-function-configuration --function-name receipt-action --environment Variables={ADMIN_TOKEN=...}
S3 & CloudFront Cache Management
After updating HTML with new credentials:
- Pushed updated
index.htmlto the S3 bucket - Invalidated the CloudFront distribution cache using wildcard paths (
/*) to ensure tenants receive the latest credentials immediately - Verified the distribution status before confirming deployment completion
Key Architectural Decisions
Why Static Credential Storage? The tenant hub doesn't require a backing database. Static HTML credentials with client-side verification reduce operational complexity and attack surface. For a small number of tenants, this is more maintainable than a full authentication service.
Why Zelle Email Forwarding? Bank transaction confirmations are already structured, timestamped, and immutable. By forwarding them through GAS, we create an audit trail (email receipt in the inbox) while automating logging. This is sexier than manual entry and requires zero new user behavior beyond forwarding an existing email.
Why Domain Isolation? Separating dangerouscentaur.com from the shared queenofsandiego.com infrastructure eliminates cross-tenant concerns, improves email deliverability (fresh domain reputation), and keeps accounting data within a single tenant's namespace. This is critical for properties managed independently.
Why GAS as the Email Handler? Google Apps Script provides free email monitoring, built-in OAuth, and direct Lambda invocation capabilities. It avoids spinning up additional infrastructure while keeping the system within Google's free tier.
Verification & Testing
Before going live:
- Smoke-tested the Lambda
log_paymentendpoint with a sample Zelle email payload - Verified SES sender identity status (confirmed DKIM records were properly added)