Software
Türkçe okuPassport Credentials and Digital Wallets: Issuer–Holder–Verifier Architecture
We examine JWT generation, the MongoDB wallet, and the claim presentation flow in the FastAPI prototype; we explain the requirements for an asymmetric signature, holder binding, selective disclosure, replay protection, and credential status for a true Verifiable Credential architecture.
Digital Travel Architecture — Part 2
In the first part of this series, we discussed how data read from an ePassport chip is verified and normalized using Passive Authentication. The next step is to convert this verified data into a Passport Credential that can be transferred to a digital wallet and verified by an airline or airport when necessary.
The FastAPI prototype we’re using as a reference visualizes this workflow using a JWT, a MongoDB-based wallet, and a simple presentation endpoint. This structure is a good starting point for understanding architectural roles; however, the concepts of “signed JWT,” “Verifiable Credential,” and “selective disclosure” are not the same. In this article, using the working demo, we will clearly distinguish the boundaries of the production-level Issuer–Holder–Verifier model.
1. Three Roles, Three Distinct Trust Responsibilities
Passport Issuer
│ doğrulanmış pasaport claim'lerini imzalar
▼
Holder / Digital Wallet
│ credential'ı saklar ve sunum için kullanıcı onayı alır
▼
Verifier
│ imza + durum + holder binding + kullanım politikasını doğrular
▼
Airline / Airport işlemi
The Issuer is the source of the claims within the credential. In the Digital Travel scenario, this role can be assumed directly by a government authority, an authorized digital identity service, or a trusted derivation service. The Issuer’s signature not only indicates that the data has not been altered subsequently but also that specific claims were made by a specific authority.
The Holder is the party that possesses the credential and presents it to the Verifier. In most scenarios, the Holder is the traveler; however, it should be noted that the Holder and the credential subject do not always have to be the same.
The verifier is the airline, airport, border control system, or other authorized service that receives the credential. In the W3C model, successful cryptographic verification does not mean that the claims are automatically sufficient for a specific transaction. The verifier also evaluates issuer trust, validity period, credential status, and its own business policies.
2. How is a demo credential generated?
A common payload generator in the prototype iss, sub, iat, exp, vc_type and claims fields. Then, an HS256 signature is generated using PyJWT:
def build_payload(subject_id, vc_type, claims, ttl):
now = int(time.time())
return {
"iss": "did:example:issuer",
"sub": subject_id,
"iat": now,
"exp": now + ttl,
"vc_type": vc_type,
"claims": claims,
}
token = jwt.encode(payload, shared_secret, algorithm="HS256")
The strength of this approach lies in its simplicity. The token can be transported in a compact format, validity checks can be performed using standard JWT libraries, and throughout the prototype, Passport, Loyalty, and Order credentials can be generated using the same mechanism.
However, this object is not a full implementation of the W3C Verifiable Credentials Data Model 2.0. The W3C model defines concepts such as issuer, credential subject, type, validity, status, and securing mechanism; the credential format and exchange protocol to be used must also be selected. Therefore, it is more accurate to refer to the structure in the prototype as a “JWT-based demo credential.”
3. Why is HS256 not the right trust model for production?
HS256 is a symmetric algorithm: the party signing the token and the party verifying it both know the same secret key. When this key is shared to grant verification authority to an airline, that same airline could theoretically generate new credentials as well. The separation of authority between the issuer and the verifier is lost.
In the production architecture, the issuer signs with the private key, while the verifier uses only the public key:
{
"alg": "ES256",
"kid": "https://issuer.example/keys/2026-07"
}
kid, which helps the verifier find the correct public key. The private key must be stored in an HSM or a suitable key management service; key rotation, algorithm policy, audit logging, and emergency revocation procedures must be part of the design. The issuer’s identity should not be accepted solely by relying on a string within the payload; it must be linked to trusted metadata and key material.
4. Adding to a wallet is not the same as holder binding
The demo frontend first generates the Passport JWT, then adds it to a separate endpoint via a separate call /wallet/{user_id}/add to its endpoint. The backend verifies the token’s signature and stores the following logical structure in MongoDB:
{
"user_id": user_id,
"vc_type": "passport",
"vc_jwt": token,
"description": "Passport VC"
}
Writing a token to a user collection does not cryptographically prove that the user is the legitimate owner of the credential. If there is no authentication or authorization at the endpoints, it may also be possible to add a token to another person’s wallet record or list the contents of a wallet.
Cryptographic holder binding ties the credential to a key controlled by the holder. During wallet issuance, a key pair is generated or a secure device key is used; the issuer associates the credential with this public key. During presentation, the wallet proves control of the private key. Thus, simply copying the token file is not sufficient to use the credential.
Issuance protocols such as OpenID4VCI can be used to standardize the authorization, credential endpoint, issuer metadata, and proof-of-possession steps. Policies for secure devices, key backup, and device replacement must be designed separately.
5. What does the demo “presentation” endpoint do?
The endpoint in the wallet router present identifies the requested credential type, validates the JWT, and required_claims returns JSON by selecting fields from its list:
claims = payload.get("claims", {})
if request.required_claims:
claims = {
key: value
for key, value in claims.items()
if key in request.required_claims
}
return {
"vc_type": request.vc_type,
"subject_id": payload["sub"],
"claims": claims,
"issuer": payload["iss"],
}
This is useful for demonstrating the concept of data minimization; however, it is not cryptographic selective disclosure. The server decrypts the original signed token and generates a new unsigned JSON object. The verifier cannot independently prove that these fields were actually signed by the issuer; it must rely on the wallet service.
In the SD-JWT VC approach, the issuer binds selectable claims to the credential using hash-based disclosure structures. The holder provides only the necessary disclosures; the verifier verifies that the disclosed claims are bound to the issuer’s signature. SD-JWT VC is still in the IETF Internet-Draft process; the version to be used and the compliance profile must be finalized within the scope of the project.
6. How does this relate to presentation replay attacks?
A Passport Credential or presentation must not be compromised and replayed in another transaction. In a secure presentation flow, the verifier sends a nonce and its own identity. The wallet binds the presentation to these values:
Verifier → Wallet:
client_id, nonce, istenen credential ve claim'ler
Wallet → Verifier:
seçilmiş disclosure'lar,
holder key proof,
client_id + nonce'a bağlı presentation
OpenID4VP 1.0 requires that the presentation be linked to the verifier’s client_id and nonce values. This ensures that a response generated for a check-in session cannot be reused with a different airline or at a later time. Additionally, it must be clearly shown to the user which verifier is requesting which claims.
7. Credential verification is not the same as a travel decision
The verifier must perform the following checks separately:
- Does the credential format and schema match the expected profile?
- Is the issuer’s signature verified using a trusted key?
- Is the credential still valid, or has it expired?
- Has the credential been revoked or suspended?
- Is the presentation nonce tied to the verifier’s identity?
- Does the holder prove control over the key associated with the credential?
- Are the declared claims sufficient and necessary for this transaction?
- Do the Travel Rules and airline policy permit travel?
The first six items primarily concern the authenticity of the credential and the security of its presentation. The last two items are business decisions. A “signature valid” result should never, on its own, mean “the passenger can fly.”
8. Credential Status and Privacy
A passport may be lost, revoked, or the credential may be linked to the wrong wallet. exp verification alone does not resolve these situations. The credential status mechanism must be able to indicate revocation and suspension statuses.
However, status checks also pose a privacy risk. If the verifier queries the issuer about a specific credential at every presentation, the issuer can track where and when the passenger performed a transaction. The W3C VC Data Model 2.0 specifically emphasizes that the status mechanism must not allow for the tracking of individuals’ usage. Privacy-preserving methods, such as bitstring-based aggregate status lists, are therefore important.
9. Secure Evolution Plan for the Reference Prototype
- Generate Passport Credential claims from a verified chip session rather than a user form.
- Use asymmetric issuer keys instead of HS256,
kidand use trusted metadata. - Add strong authentication, authorization, and tenant isolation to wallet endpoints.
- Bind the credential to the wallet’s device key using a cryptographic holder binding.
- Use an SD-JWT VC or another selective disclosure format appropriate for the selected profile instead of simple claim filtering.
- Add the verifier ID, nonce, audience, and replay cache to the presentation flow.
- Establish privacy-preserving credential status and key rotation processes.
- Define separate schemas, issuer policies, and lifecycles for Passport, Loyalty, and Order credentials.
Result
The reference implementation makes the Issuer–Holder–Verifier chain visible: the backend generates credentials, the wallet stores them, and selected claims are presented to the verifier. For production security, four additional links are required: linking the credential to a verified passport session, linking the credential to the holder’s key, linking the presentation to the verifier and nonce, and linking the verifier’s decision to the current travel rules policy.
In the third part of the series, we will examine how the Loyalty Credential affects flight offers and explore the generation of the Order Credential. In particular, we will demonstrate why obtaining the price from the client as “trusted data” is risky and how offer–order integrity is established.
Official Sources
How would you rate this article?
Your feedback helps improve future articles.