Skip to main content

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_claim JWT signed ES256 with the participant's DID-bound key
  • iss = 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.

CredentialRole
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)

  1. The dashboard backend calls the Gateway with the user's token.
  2. The Gateway re-validates the token against the consumer Keycloak JWKS.
  3. It initiates the EDC transfer for the agreement and receives an EDR.
  4. It persists a session (EDR encrypted at rest) and returns a bootstrap_url.

Phase 2 — per-request proxy (browser-driven, every request)

  1. The browser hits the Gateway on its own origin at /proxy/{sid}/.
  2. The Gateway validates the user token and looks up the session.
  3. It forwards through the provider data plane with the EDR and a signed identity claim.
  4. 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:

  1. The user authenticates against the consumer's own Keycloak; the Gateway re-validates the token against its JWKS.
  2. For each proxied request, the Gateway forges a JWT with the user's claims, signed ES256 with kid=key-1 and iss=did:web:<participant>.
  3. It travels in X-Dataspace-Identity through the data plane; the provider edge rewrites it to Authorization: Bearer.
  4. The backend resolves the issuer's did:web document, picks the verificationMethod matching the kid, and verifies the signature against its publicKeyJwk.
  5. 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.

BlockWhat it does
W3C DID — did:web identityThe signing participant is named by iss=did:web:<participant>; verifiers discover its public key by resolving /.well-known/did.json.
Participant EC P-256 keyThe 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 signaturesShort-lived bootstrap JWTs are signed and verified with ES256 against the publicKeyJwk published in the DID document.
EDC Dataspace ProtocolThe EDR is negotiated machine-to-machine between consumer and provider connectors over DSP.
EDC data plane — proxyForwardedHeadersEvery browser request transits the provider data plane; the signed claim rides in X-Dataspace-Identity via the forwarded-headers feature.
ODRL — runtime enforcementBecause 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 →

note

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.