Gateway — Web browsing over EDC
The TEMS Gateway lets a user from one participant browse a web application published by another, through the EDC data plane, so ODRL policies are re-evaluated on every request. Identity is carried with Data Space and DID primitives, and the data-plane credential never reaches the browser.
Key facts
signed_claimJWT signedES256with the participant's DID-bound keyiss = did:web:<participant>- EDR stays server-side
- ODRL re-evaluated per request
1. The problem: one header, two credentials
Serving an interactive web application as a dataspace offering puts two runtime credentials on the same request. The HTTP Authorization header holds one value, so they cannot share it.
| Credential | Role |
|---|---|
Authorization: Bearer <user JWT> | The web app authenticates the user against its own identity provider. |
Authorization: Bearer <EDR> | The EDC data plane validates the contract and re-evaluates ODRL. |
RFC 9110 §11.6.2 — the field carries a single credential. The two cannot share it.
Two constraints frame the solution:
- The EDR is a server-side credential. Short-lived and scoped to a contract negotiation. Placing it in the browser would break its security model.
- The backend application is not rewritten for TEMS. It keeps validating a standard bearer token. The dataspace plumbing stays outside the application.
2. The solution: consumer-side bridge in two phases
The Gateway runs as a sidecar on the consumer participant. It accepts the user's token on one side, holds the EDR on the other, and routes through the EDC data plane in between.
Phase 1 — bootstrap (server-to-server, one-shot)
- The dashboard backend calls the Gateway with the user's token.
- The Gateway re-validates the token against the consumer Keycloak JWKS.
- It initiates the EDC transfer for the agreement and receives an
EDR. - It persists a session (EDR encrypted at rest) and returns a
bootstrap_url.
Phase 2 — per-request proxy (browser-driven, every request)
- The browser hits the Gateway on its own origin at
/proxy/{sid}/. - The Gateway validates the user token and looks up the session.
- It forwards through the provider data plane with the EDR and a signed identity claim.
- The data plane re-evaluates ODRL and proxies to the backend application.
Runtime request path
The <user JWT> and <signed claim> are user-identity JWTs (cyan above). The <EDR> is the EDC contract-bound token — server-side only, never reaches the browser. The provider data plane re-evaluates ODRL on every hit.
3. Identity translation by signed claim
The user's consumer-Keycloak token is not presented to the provider backend. The Gateway forges a short-lived JWT carrying the user's claims, signed with the participant's own DID key. The backend validates it by resolving that DID.
// header
{
"alg": "ES256",
"kid": "key-1",
"typ": "JWT"
}
// payload
{
"iss": "did:web:<participant>",
"sub": "<user-id>",
"preferred_username": "<username>",
"exp": "<short TTL>"
}
// signed with the participant's EC P-256 private key
// (the same key the Identity Hub uses for DCP)
The full lifecycle:
- The user authenticates against the consumer's own Keycloak; the Gateway re-validates the token against its JWKS.
- For each proxied request, the Gateway forges a JWT with the user's claims, signed
ES256withkid=key-1andiss=did:web:<participant>. - It travels in
X-Dataspace-Identitythrough the data plane; the provider edge rewrites it toAuthorization: Bearer. - The backend resolves the issuer's
did:webdocument, picks theverificationMethodmatching the kid, and verifies the signature against itspublicKeyJwk. - Trust is an explicit allow-list of issuer DIDs. No Keycloak federation and no per-participant client registration are involved.
4. Data Space and DID building blocks
The solution composes existing dataspace primitives. It introduces no new key material and no new identity authority.
| Block | What it does |
|---|---|
W3C DID — did:web identity | The signing participant is named by iss=did:web:<participant>; verifiers discover its public key by resolving /.well-known/did.json. |
| Participant EC P-256 key | The Gateway signs with the participant's own key — the same keypair the Identity Hub uses for DCP tokens and verifiable presentations. kid=key-1, no new key. |
| JOSE — ES256 signatures | Short-lived bootstrap JWTs are signed and verified with ES256 against the publicKeyJwk published in the DID document. |
| EDC Dataspace Protocol | The EDR is negotiated machine-to-machine between consumer and provider connectors over DSP. |
EDC data plane — proxyForwardedHeaders | Every browser request transits the provider data plane; the signed claim rides in X-Dataspace-Identity via the forwarded-headers feature. |
| ODRL — runtime enforcement | Because the data plane stays on the request path, ODRL policies are re-evaluated per request rather than once at acquisition. |
Want the implementation detail?
The signed-claim JWT contract, the did:web validation algorithm with code for Python, JVM and Node, the edge rewrite, and the trust model — all in the Integration guide →
The gateway's deeper internals (architecture decisions, EDC data-plane flow, ADRs) live in the private tems-gateway repository's docs/ folder and are internal to the consortium.