Session-to-service token bridging in the BFF
What this process is
- Session-to-service token bridging in the BFF.
- The BFF validates the SPA’s session cookie, then proxies the request to a backend
target_serviceusing a service‑scoped access token (audience‑bound to that service). It maps tokens per service name and attaches the correctAuthorizationheader on the upstream hop.
What this is not
- The service token is not the user’s identity. The user identity comes from
id_token.substored in the BFF session. Service tokens often havesub = client_id(e.g.,bff-server), which is expected.
Why it’s needed
- Backends require OAuth access tokens and will not accept your browser cookie (e.g., Analytics, CRUD, PDP).
- The BFF holds the user session and, on behalf of the user, mints/keeps per‑service tokens. Without a mapped token for the specific
target_service, the BFF logsNO_TOKEN_AVAILABLEand returns401.
How it works (runtime flow)
- SPA calls a canonical BFF route (for example,
GET /api/v1/analytics/workflows). - BFF matches the YAML route, sets
target_service=analytics_service, and requires session auth. - BFF looks up a token in the session store keyed by
target_service.- If a token exists and its
audmatches Analytics, the BFF injectsAuthorization: Bearer <token>and forwards. - If not, you see in logs:
service=analytics_service NO_TOKEN_AVAILABLE → 401.
- If a token exists and its
What must be configured (BFF + IdP)
Goal: Align audiences/scopes so the BFF can mint and map a token for the service name used in routes.yaml.
1) BFF route to target_service
- File:
ServiceConfigs/BFF/config/routes.yaml - Ensure a route exists and points to the logical service name the BFF uses for token lookup:
# Already correct
services:
analytics_service:
base_url: "http://analytics:8100"
routes:
- id: "api-analytics"
path: "/api/v1/analytics/*"
target_service: "analytics_service"
upstream_path: "/api/v1/analytics/{path}"
auth: "session"
2) IdP: allow audience issuance for that service
- File:
ServiceConfigs/IdP/config/settings.yaml - Map a scope you grant at login (for example,
application.all) to include the Analytics audience so the IdP can issue a token for it.
token:
audience_mappings:
scope_mappings:
- scope: application.all
audiences:
- https://idp.ocg.labs.empowernow.ai/api/admin
- https://idp.ocg.labs.empowernow.ai/api/v1
- https://crud.ocg.labs.empowernow.ai
- empowernow
- https://analytics.ocg.labs.empowernow.ai # added
3) IdP: allow the BFF client to request that audience
- File:
ServiceConfigs/IdP/config/clients.yaml(client:bff-server)
bff-server:
# ...
scopes: [openid, profile, email, offline_access, admin.api, application.all]
allowed_audiences:
- empowernow
- https://analytics.ocg.labs.empowernow.ai # added
4) BFF: service → audience mapping (token minting/validation)
- File:
ServiceConfigs/BFF/config/<settings file>(the BFF reads aservice_audiencesmap used bysession_manager.get_service_audience(service)) - Add Analytics mapping so the BFF knows which audience to request/validate for
analytics_service:
service_audiences:
crud_service: https://crud.ocg.labs.empowernow.ai
pdp_service: https://authz.ocg.labs.empowernow.ai/api/v1
idp_service: https://idp.ocg.labs.empowernow.ai/api/v1
analytics_service: https://analytics.ocg.labs.empowernow.ai # add this
service_scopes:
analytics_service: application.all # or api.read if you enforce finer scope
- Names must match the
target_serviceinroutes.yaml(analytics_service).
Example: Analytics
- Symptom: BFF logs show
NO_TOKEN_AVAILABLE service=analytics_service → 401. - Fix you made:
- Added Analytics audience to IdP
application.alland tobff-server.allowed_audiences.
- Added Analytics audience to IdP
- Remaining step (BFF config):
- Add
analytics_service → https://analytics.ocg.labs.empowernow.aiin BFFservice_audiences(and optionalservice_scopes).
- Add
- Restart IdP and BFF; log out/in once so the session refreshes and tokens are minted.
- Re‑test. BFF logs should show
token_found=Trueforanalytics_serviceand upstream200.
Troubleshooting
- If route is correct but still 401:
- Check BFF log line:
NO_TOKEN_AVAILABLE service=analytics_service. That means theservice_audiencesmap or IdP audience/scopes are not aligned.
- Check BFF log line:
- If
token_found=Truebut upstream401:- Check the audience value matches the backend’s required
audexactly.
- Check the audience value matches the backend’s required
- Verify
services_countin “Session status check successful” includes analytics after login.
Quick checklist
- BFF
routes.yaml:target_servicepresent and correct. - IdP
settings.yaml: scope → audience mapping includes the service audience. - IdP
clients.yaml(bff-server):allowed_audiencesincludes the service audience. - BFF settings:
service_audiences(andservice_scopes) include the service name used by routes. - Restart IdP and BFF; re‑authenticate.
See also
services/bff/explanation/authentication.mdservices/bff/how-to/spa-with-bff.md