Internal Service Authentication
Relevant source files
The following files were used as context for generating this wiki page:
Internal Service Authentication is a security mechanism used to facilitate secure communication between the Frontend (Next.js) and the Backend (FastAPI) services. Because these services operate in a distributed two-service architecture, the application employs a signed request pattern to verify that requests originating from the frontend are legitimate and authorized.
The system relies on a shared secret key, INTERNAL_AUTH_SECRET, which is used to generate and verify HMAC-SHA256 signatures. This ensures that the backend can trust the identity of the user passed from the frontend without exposing the backend directly to public traffic without protection.
Sources: README.md:105-115, CLAUDE.md:10-30, frontend/lib/internal-auth.ts:14-20
Architecture and Configuration
The authentication flow is integrated into the infrastructure layer of the project. Both services must be configured with the same secret to successfully handshake.
Shared Configuration
The system uses environment variables to distribute the necessary credentials across services. In production environments like Docker Compose or Railway, these are managed as secrets.
| Variable | Description | Source |
|---|---|---|
INTERNAL_AUTH_SECRET | Shared secret used to generate/verify signed requests | README.md:195 |
BACKEND_URL | The internal URL of the FastAPI service | deploy/compose/docker-compose.yml:104 |
x-syllogic-user-id | Header containing the authenticated user's ID | frontend/lib/internal-auth.ts:3 |
x-syllogic-signature | Header containing the HMAC signature | frontend/lib/internal-auth.ts:5 |
Sources: deploy/compose/docker-compose.yml:100-110, frontend/lib/internal-auth.ts:3-6
Authentication Flow
When the frontend needs to communicate with the backend (e.g., for transaction enrichment or data syncing), it generates a signature based on the request method, path, user ID, and a timestamp.
The diagram shows the synchronous flow of signing a request on the frontend and verifying it on the backend using the shared secret.
Sources: frontend/lib/internal-auth.ts:22-45, deploy/railway/docker-compose.yml:55-65
Signature Implementation
The signature generation logic is centralized in the frontend library. It uses a specific payload structure to ensure that the signature is unique to the specific request and expires over time (via the timestamp).
Payload Structure
The payload is constructed by joining specific request attributes with newline characters:
- Method: The HTTP method (e.g., GET, POST) in uppercase.
- Path: The request path including query parameters.
- User ID: The ID of the currently authenticated user.
- Timestamp: A Unix timestamp (seconds).
Sources: frontend/lib/internal-auth.ts:22-29
Header Generation
The createInternalAuthHeaders function handles the creation of the final headers required by the backend.
export function createInternalAuthHeaders({
method,
pathWithQuery,
userId,
timestamp = Math.floor(Date.now() / 1000).toString(),
}: InternalAuthSignatureInput): Record<string, string> {
const secret = getInternalAuthSecret();
const payload = [method.toUpperCase(), pathWithQuery, userId, timestamp].join("\n");
const signature = createHmac("sha256", secret)
.update(payload)
.digest("hex");
return {
[INTERNAL_AUTH_USER_HEADER]: userId,
[INTERNAL_AUTH_TIMESTAMP_HEADER]: timestamp,
[INTERNAL_AUTH_SIGNATURE_HEADER]: signature,
};
}
Sources: frontend/lib/internal-auth.ts:31-52
Infrastructure Integration
The INTERNAL_AUTH_SECRET is defined as a required variable in all deployment manifests. If this variable is missing, the services will fail to start or throw errors during the signing process.
Docker Compose
In the standard deployment, the secret is passed to both the backend and app (frontend) containers.
backend:
environment:
INTERNAL_AUTH_SECRET: ${INTERNAL_AUTH_SECRET:?set INTERNAL_AUTH_SECRET in .env}
app:
environment:
INTERNAL_AUTH_SECRET: ${INTERNAL_AUTH_SECRET:?set INTERNAL_AUTH_SECRET in .env}
Sources: deploy/compose/docker-compose.yml:58, 103
Installation Script
The automated install script generates a secure random 32-character hex string for the internal secret during initial setup to ensure a unique security key for every installation.
INTERNAL_AUTH_SECRET="$(openssl rand -hex 32)"
Sources: deploy/install/install.sh:65
Conclusion
Internal Service Authentication provides a critical security layer for the Syllogic application, ensuring that the FastAPI backend only processes requests validated by the Next.js frontend. By using HMAC-SHA256 signatures with a shared secret, the system maintains a stateless yet secure bridge between its two primary services.