Stateless backend-for-frontend (BFF) for OpenFGC Portal, responsible for handling portal-facing authentication flows and securely proxying API requests from portal/frontend to /consent-server.
task fmttask fmt:check(no edits. check only)task linttask lint:install(optional, installs golangci-lint to GOPATH/bin)task testtask buildtask runtask run:env(loads variables from.envfor local development)
Install Task if needed: https://taskfile.dev/installation/
- Primary source:
BFF_environment variables - Optional file overlay: set
BFF_CONFIG_FILEto a YAML config file path - Final effective config is: defaults < file < env
When running portal/frontend on a different origin (for example Vite dev server), allow that origin with:
BFF_CORS__ALLOWED_ORIGINS(comma-separated origins)BFF_CORS__ALLOWED_METHODS(comma-separated methods)BFF_CORS__ALLOWED_HEADERS(comma-separated request headers)BFF_CORS__ALLOW_CREDENTIALS(true/false)
Requests that include an Origin header from a non-allowlisted origin are rejected.
When credentials are enabled, origins must be explicitly allowlisted (wildcard origin is rejected).
GET /healthGET /health/livenessGET /health/readiness
Portal-facing user endpoints:
GET /me/consents-> upstreamGET /api/v1/consentswith forceduserIds=<placeholder>GET /me/consents/{consentId}-> upstreamGET /api/v1/consents/{consentId}POST /me/consents/{consentId}/approve-> BFF fetches current consent, merges selected optional approvals, uses the consent'sclientIdas the trusted upstreamTPP-client-id, updates an existing authorization to approved for the trusted user (or creates one if none exist), and upstreamsPUT /api/v1/consents/{consentId}PUT /me/consents/{consentId}/revoke-> upstreamPUT /api/v1/consents/{consentId}/revoke
Proxy hardening:
- Path rewrite
/api/*->/api/v1/*with query preservation - Deny-by-default allowlist for consent-server routes (unknown path ->
404, known path wrong method ->405) - Hop-by-hop header stripping and trusted-header override prevention (
org-id,TPP-client-id) - Correlation ID propagation/generation via
X-Correlation-ID - Request body limit enforcement (
BFF_PROXY__MAX_REQUEST_BYTES) with413 - Deterministic upstream error mapping: timeout ->
504, other connectivity failures ->502
Error contract for proxy-originated failures:
{
"code": "REQUEST_TOO_LARGE",
"message": "request entity too large"
}Common error codes:
REQUEST_TOO_LARGEMETHOD_NOT_ALLOWEDNOT_FOUNDINVALID_PAYLOADUPSTREAM_TIMEOUTUPSTREAM_UNAVAILABLE
BFF_PROXY__PLACEHOLDER_MODE_ENABLED=trueis blocked whenBFF_ENV=productionBFF_PROXY__PLACEHOLDER_USER_IDmust be empty if placeholder mode is disabled
This repository uses VS Code Copilot instruction files to keep AI-generated changes aligned with project and organization standards.
- Backend standards:
portal/backend/AGENTS.md - Copilot workspace entrypoint (repo root):
.github/copilot-instructions.md - Scoped instructions folder (repo root):
.github/instructions/ - Backend scope mapping:
portal/backend/**->.github/instructions/portal-backend.instructions.md
Copilot instructions are discovered automatically and scoped using applyTo patterns.