security·12 min read

QWAC vs QSealC: who does what, and why you've got the wrong layer

The QWAC is read by the TLS layer, once, at the handshake. The QSealC is read by the application layer, on every request. Where each private key lives, what STET requires, and how to read a 'certificate error'.

Both certificates come from the same eIDAS TSP, carry the same authorisation number and the same DSP2 roles, and often arrive on the same purchase order. The difference is not in what they contain. It is in which layer of the stack reads them. The QWAC is read by the TLS layer, once, at the handshake. The QSealC is read by the application layer, on every request, in an HTTP header.

A ticket that says "certificate error" without saying which layer cannot be diagnosed. This article does not redefine the two objects — the QWAC, QSealC and mTLS glossary entries do that. It places each one in the stack, in the infrastructure and in the logs, with the STET 1.6.3 text alongside. For the full picture of the stack, read Technical architecture of a PSD2 API first.

In one picture: two layers, two certificates

A PSD2 request goes down the stack. Each certificate comes into play at one level only.

QWACQSealC
eIDAS basisqualified website authentication certificate, art. 3(39)qualified electronic seal certificate, art. 3(30)
Layertransport (TLS)message (HTTP)
Read bythe TLS stack on both sides, at the handshakethe signature verifier of the ASPSP, on every request
Frequencyonce per connectiononce per request — and per response if the ASPSP signs
Survives a proxy that terminates TLSnoyes
Evidential value after the factnone: nothing is keptthe signature stays in the request, verifiable later
Private key, on the TPP sidewhere the outbound connection is openedwhere the request is built
Symptom when it breaksbroken handshake, no HTTP status codeHTTP 400 (STET §3.5)
What STET says about it§3.1, §3.2, §3.9§3.5

RTS (EU) 2018/389, art. 34, allows either one for identification. The API standards settled the question by stacking them: STET and the Berlin Group require the QWAC for the channel and the QSealC for the signature. Two certificates, hence two private keys, two expiry dates and two rotation procedures.

What STET requires, text in hand

Three passages of the 1.6.3 Framework (Part 1) are enough. Page numbers are those of the official PDF, which the handbook displays in the margin of each paragraph.

§3.1 and §3.2 — the QWAC, for TLS and nothing else

"Each actor must be provided with at least one eIDAS certificate (QWAC), for TLS 1.2 purpose" (§3.1, p. 17). The TPP verifies the ASPSP's server QWAC and presents its own; both comply with ETSI TS 119 495; "in case of authentication failure, on one side or the other, the connection must be closed"; and "no additional encrypting or authenticating feature is required" (§3.2, p. 17–18). The QWAC never surfaces in the request: everything it has to say, it says at the handshake.

The same paragraph fixes the format of the certificate subject's organizationIdentifier: PSD, the country code of the NCA, a hyphen, the NCA identifier, a hyphen, the authorisation number — PSDFR-ACPR-12345 for an actor authorised by the ACPR. This field, together with the roles in the ETSI QC statement, is what the ASPSP reads in the client certificate to know who is calling, and in what capacity.

§3.5 — the QSealC, to sign every request

"Each request sent by the TPP has to be signed and ASPSP might also sign their responses. If the ASPSP notes that the signature is either absent or invalid for a given request, it shall reject this request with HTTP400" (§3.5, p. 53).

The historical mechanism is HTTP Signature in its draft-cavage version: a SHA-256 Digest of the body, then an RSA-SHA256 signature computed with the QSealC over (request-target), Date, Content-Type, Content-Length, X-Request-Id, the PSU-* headers and the Digest itself, carried in the Signature header along with keyId, algorithm and the list of signed headers (§3.5.1.1, p. 53–55). The keyId is either the identifier assigned at OAuth2 registration, or the URL of the QSealC suffixed with a _ and its SHA-256 fingerprint (§3.5.1.2, p. 55).

Since 1.6.3, the Framework recommends replacing this mechanism with the Open Banking Europe JSON Web Signature profile: a detached JWS (RFC 7515) in the x-jws-signature header, whose protected header carries x5t#S256, the fingerprint of the signing QSealC, and sigD, the list of covered headers (§3.5.2, p. 55–56). As for draft-cavage, the IETF has superseded it with RFC 9421 — which STET does not cite as a target.

§3.9 — the QWAC comes back a third time, in OAuth2

"Based on MTLS, the identity of the TPP is provided by its eIDAS certificate during OAuth2 procedures", with a reference to RFC 8705 (§3.9, p. 59). The authorisation server therefore authenticates the client through tls_client_auth — the QWAC presented at the handshake of the POST /token — and can bind the issued token to that certificate, via its cnf claim and the x5t#S256 fingerprint. A token bound to a fingerprint that is no longer the one presented is rejected, even if it has not expired.

One request, three checks

Three checks, three layers, three symptoms that look nothing alike. The order of the two application-level checks varies from bank to bank; the symptom does not.

Where the private keys live: the layer mistake

This is where the mistake happens. The two private keys do not live in the same place, because the two certificates are not read by the same component.

On the TPP side, outbound

The QSealC key belongs to the component that builds the request, because the signature covers headers — Date, Content-Length, X-Request-Id — that must be frozen before sending. The QWAC key belongs to the component that opens the connection. If an egress proxy, an application-level NAT or a service mesh opens the connections on the application's behalf, it is that component that presents the QWAC, and the application has no business holding the key. Putting the QWAC key in the application while the mesh terminates and re-opens TLS yields a handshake with no client certificate: a TLS alert, and no HTTP status code.

On the ASPSP side, inbound

On the bank side, the client QWAC stops at the component that terminates TLS. What travels onward is an extracted identityorganizationIdentifier, roles, fingerprint — carried in an internal header that the rest of the chain must be able to trust, hence the point of signing it, or of accepting it only from the terminator. The QSealC signature, on the other hand, goes all the way through: a component anywhere behind can verify it, provided it sees the original bytes. A gateway that re-serialises the JSON, recomputes Content-Length or normalises Date before the verifier produces 400s on valid requests.

The six layer confusions

#ConfusionWhat happensSymptom
1QWAC key on a component that does not open the connectionhandshake with no client certificateTLS alert, no HTTP
2QSealC presented as the TLS client certificate, or QWAC used for signingthe ETSI QcType is the wrong one (web for one, eseal for the other); a verifier that checks it refusesTLS alert, or 400
3Signature computed before a proxy that rewrites Date, Content-Length or the bodythe signature covers different bytes from those received400, invalid signature
4Verification done after a transformation of the request, on the ASPSP sidesame cause, mirrored400 on valid requests
5QWAC renewed without reissuing the bound tokenscnf.x5t#S256 no longer matches the certificate presented401 on an unexpired token
6The bank's QTSP CA missing from the TPP's trust storethe TPP refuses the ASPSP's server QWACunknown_ca, connection closed by the TPP itself

Confusion 2 is the most expensive, because it is invisible as long as the bank does not check the certificate type — and visible all at once the day it does. The two certificates are often sold together; they are not interchangeable.

Diagnostic matrix

SymptomLayerCertificate involvedWhere to look
Connection closed during the handshake, no HTTP status code; handshake_failure, bad_certificate, certificate_expired, unknown_caTLSQWAC — yours, or the bank's that you do not recogniseTLS terminator logs; openssl s_client -cert -key
401tokenQWAC, via the RFC 8705 binding; or simply an expired tokenauthorisation server response; the token's cnf against the fingerprint of the certificate presented
400 mentioning the signature (STET §3.5)HTTP messageQSealCrecomputed Digest; list of signed headers; resolvable keyId; bytes actually sent
403, or the bank's business error codeauthorisationneitherthe certificate's PSD2 roles against the endpoint called; consent state

Two clocks

The two certificates each expire on their own date, can each be revoked on their own, and are renewed separately. Three consequences:

  • Two expiry alerts, not one. A valid QWAC says nothing about the state of the QSealC, and vice versa.
  • Rotating the QWAC affects the tokens. The OAuth2 registration survives if the subject DN does not change — that is what tls_client_auth_subject_dn declares — but the access tokens bound to the old fingerprint (RFC 8705) no longer go through. Reissuing the tokens is part of the rotation.
  • Rotating the QSealC affects the keyId — the fingerprint-suffixed URL changes, or the x5t#S256 of the JWS profile — and it must not withdraw the old certificate: requests already signed must remain verifiable. That is the whole point of non-repudiation. The private key is withdrawn; the certificate stays published.

To sum up

  1. QWAC = TLS layer. Read at the handshake, by the component that opens or terminates the connection. Its key lives there, nowhere else.
  2. QSealC = message layer. Read on every request, by a verifier that must see the original bytes. Its key lives where the request is built.
  3. STET: QWAC for TLS 1.2 (§3.1–3.2), every request signed with the QSealC and 400 otherwise (§3.5), JWS profile recommended since 1.6.3 (§3.5.2), OAuth2 identity carried by the QWAC (§3.9, RFC 8705).
  4. No HTTP status code → QWAC. 400 → QSealC. 401 → token binding. 403 → neither.
  5. Two clocks: two expiries, two rotations, and the old QSealC stays published to verify the past.

For the rest of the stack — standards, SCA flows, consent — see Technical architecture of a PSD2 API. The two signature mechanisms, byte by byte, and the most frequent handshake failures are the subject of the next two articles. The full text of the section quoted is in the STET 1.6.3 handbook, with the original PDF alongside.

#dsp2#psd2#open-banking#security#eidas#mtls#stet
Trending

Read next

Expand your knowledge with these hand-picked posts.

April 7, 2026
technical

Technical architecture of a PSD2 API: what to know before writing the first line of code — Read more

A technical overview of PSD2 for CTOs, developers and technical PMs: API standards, security (mTLS, eIDAS certificates), OAuth2, SCA flows, consent management, implementation pitfalls.

April 6, 2026
regulation

Understanding PSD2: what it changes for your customers and your business — Read more

Everything an executive, a product manager or a business team needs to understand about PSD2. Players, consent, opportunities, without technical jargon.