Wallet Attestation
Learn how Wallet Attestation works in MATTR Holder SDKs to enable credential claiming from issuers that require trusted wallet applications.
Overview
Wallet Attestation enables credential issuers to restrict credential issuance to trusted wallet applications only. When an issuer requires Wallet Attestation, the holder application must cryptographically prove its authenticity before it can claim credentials.
This mechanism is valuable when:
- Enforcing wallet policies: Issuers can ensure that only authorized and trusted wallet applications receive their credentials.
- Protecting against unauthorized access: Credential theft is prevented by verifying the wallet's identity before issuance.
- Leveraging platform-based attestation: Platform-specific security mechanisms (such as iOS App Attestation and Android Key Attestation) are used to authenticate app instances with the MATTR VII tenant, ensuring that only trusted wallet instances receive attestation proofs for use with issuers.
For a detailed technical breakdown of Wallet Attestation from an issuer's perspective, including attestation modes, JWT structures, and certificate trust chains, see Wallet Attestation in the Issuance documentation.
Standards and specifications
Wallet Attestation in MATTR VII is based on the following standards:
- OAuth 2.0 Attestation-Based Client Authentication: The core specification for Wallet Attestation
- RFC 9449: DPoP (Demonstrating Proof-of-Possession): DPoP specification
How it works
The following diagram illustrates the interaction between the Holder SDK, the MATTR VII tenant, and the issuer.
At the protocol level, the Wallet Attestation proof is carried as an OAuth client attestation JWT (defined in OAuth 2.0 Attestation-Based Client Authentication) combined with a DPoP proof. In the descriptions below, "client attestation JWT" refers to the token that conveys the Wallet Attestation to the issuer.
- Retrieve the credential offer: The Holder SDK retrieves the credential offer from the issuer. This offer includes a reference to the issuer's metadata endpoint.
- Check issuer metadata for attestation requirements: The Holder SDK fetches the issuer's metadata. If the metadata specifies that the issuer requires Wallet Attestation to issue credentials, the SDK proceeds with the attestation flow. If not, credential claiming continues without attestation.
- Request a Wallet Attestation token from the tethered tenant: The Holder SDK automatically makes a request to the MATTR VII tenant it is tethered to, passing the identifiers of the Holder Application configuration that were declared during SDK initialization.
- The MATTR VII tenant validates and returns the Wallet Attestation token: The MATTR VII tenant recognizes the app as a registered instance of the configured Holder Application. Assuming SDK Tethering is correctly set up, the tenant returns a signed client attestation JWT that carries the Wallet Attestation proof.
- Generate a DPoP proof and present attestation to the issuer: The Holder SDK generates a DPoP proof locally and includes both the client attestation JWT and the DPoP proof when requesting the credential from the issuer. Together these two values form the complete Wallet Attestation presented to the issuer. No additional code is required from the holder application developer.
- Issuer validates and issues the credential: The issuer validates the Wallet Attestation (client attestation JWT + DPoP proof), confirms that all requirements are met, and issues the credential to the holder application.
Setting up Wallet Attestation
Complete the following steps to enable Wallet Attestation in your holder application.
Configure SDK Tethering
Set up SDK Tethering to connect the Holder SDK to your MATTR VII tenant:
- Create Holder Applications on your MATTR VII tenant for each platform target (iOS and Android).
- Initialize the SDK with the correct
platformConfigurationincluding the tenant URL and the identifiers of the Holder Application you created.
Create and activate a Holder root CA certificate
Your tethered MATTR VII tenant must have an active Holder root CA certificate. This root CA is used to sign Wallet Attestation signers, which in turn sign the client attestation JWTs presented to issuers, forming a chain of trust.
MATTR VII supports two types of Holder root CA certificates:
- Managed: MATTR VII generates and manages the root certificate and its private key on your behalf. Wallet attestation signers are auto-provisioned when needed.
- Unmanaged (external): You supply your own root CA in PEM format. You are responsible for signing and uploading wallet attestation signer certificates.
For step-by-step instructions on creating and activating a Holder root CA, see the Holder certificates guide.
Coordinate with the issuer
Wallet Attestation requires an out-of-band coordination process between you and each credential issuer. You must complete the following before your wallet can claim credentials from issuers that require Wallet Attestation:
-
Confirm the issuer's requirements: Verify with the issuer whether Wallet Attestation is required. See Understanding issuer requirements for details on how issuer-side configuration works.
-
Share your Holder root CA certificate: Provide the public certificate of your root CA to the issuer (for example, via a secure channel or as part of a business onboarding process). The issuer uses this certificate so they can validate the attestation proof chain your SDK presents.
-
Align on the client identifier: The
clientIdyou configure on your Holder Application is included as thesubclaim in the wallet attestation JWT and is the value the issuer sees when your wallet claims a credential. The issuer must have this exact value registered against your wallet (with Wallet Attestation required) in their trusted wallet list. If the value your wallet presents and the value the issuer has registered do not match, the issuer rejects the attestation proof and credential claiming fails. See Agreeing on a client identifier for how to coordinate this value and why agreeing on it early matters.
Agreeing on a client identifier
The Wallet Attestation proof already tells the issuer which trusted wallet application is requesting
the credential. That proof is what cryptographically establishes your wallet's authenticity. The
clientId carries no additional product capability on top of this; it exists because the underlying
OAuth 2.0 Attestation-Based Client Authentication
specification requires every client to identify itself with a client_id. MATTR VII supports it so
your wallet interoperates with any spec-compliant issuer, but the choice of value is something you
and each issuer must agree on out of band.
There are two ways this coordination plays out:
-
You define the client identifier (recommended): You choose a single
clientIdfor your wallet application (for example,mattr-wallet), configure it on your Holder Application, and share it, together with your Holder root CA certificate, with each issuer during onboarding. Every issuer registers that same value, so your wallet presents one consistent identity everywhere. This keeps your integration simple: one Holder Application, oneclientId, and no per-issuer bookkeeping. -
The issuer assigns the client identifier: Some issuers insist on assigning their own value (for example, one issuer registers your wallet as
mattr-walletwhile another requirespartner-wallet-42). Because the value your wallet presents must match what each issuer has registered, supporting issuer-assigned identifiers means maintaining a separate Holder Application for each distinctclientIdand tracking which issuer expects which value. This adds operational overhead and is best avoided where possible.
Recommendation: Wherever you can, agree on a single clientId that you define and ask each
issuer to register it as-is. Raising this early in onboarding, before the issuer has provisioned
your wallet in their trusted wallet list, saves you from managing multiple Holder Applications and
per-issuer client identifier mappings later.
Important for existing integrations: If you already have a client_id registered with an
issuer from a pre-Wallet Attestation integration, we recommend registering a new client_id
for your Wallet Attestation-enabled app rather than reusing the existing one. See
Migrating to Wallet Attestation for details.
Once these steps are complete, the SDK handles all Wallet Attestation interactions automatically whenever an issuer requires it during credential claiming.
Understanding issuer requirements
Whether an issuer requires Wallet Attestation from your wallet depends on how they have configured their trusted wallets, not just on what their public metadata advertises.
- Issuer metadata (the OID4VCI
.well-knownendpoint) declares which authentication methods the issuer supports at a tenant level. For example, the issuer may advertise bothattest_jwt_client_auth_dpopandnoneas supported methods. - Per-client configuration determines what is required for any specific wallet. The issuer configures this in their trusted wallet list, associating a client identifier with a specific authentication method.
Your wallet cannot determine from public metadata alone whether Wallet Attestation is required for your specific wallet application. The issuer communicates this requirement to you as part of the onboarding process. In practice:
- If the issuer has configured your application with Wallet Attestation required, the SDK must present a valid attestation proof or credential claiming will fail.
- If the issuer has configured your application without Wallet Attestation, the SDK may still send an attestation proof (if it detects attestation support in the issuer metadata), and the issuer will simply ignore it.
- If the issuer does not support Wallet Attestation at all (not advertised in metadata), the SDK does not send an attestation proof.
Migrating to Wallet Attestation
When you enable Wallet Attestation, your SDK uses a different client authentication method
(attest_jwt_client_auth_dpop instead of none). If older app versions that do not support
Wallet Attestation share the same client identifier, and the issuer configures that client identifier to
require attestation, those older versions will fail to claim credentials.
If your holder application is already integrated with an issuer that does not require Wallet Attestation, it is recommended to use a new client identifier to migrate safely without breaking existing app versions, as described in the following steps.
Register a new client identifier with the issuer
Coordinate with the issuer to register a new client identifier (for example, my-wallet-client-v2) that will
be associated with Wallet Attestation. The issuer adds this new client identifier to their trusted
wallet list with Wallet Attestation required, alongside your existing client identifier which continues
to work without attestation.
Configure your Holder Application with the new client identifier
When creating or updating your Holder Application on your MATTR VII tenant, set the clientId
field to the new value you registered with the issuer:
{
"name": "My iOS Holder Application",
"clientId": "my-wallet-client-v2",
"type": "ios",
"bundleId": "com.yourcompany.holderapp",
"teamId": "YOUR_APPLE_TEAM_ID",
"maxTimeOfflineInSecs": 864000,
"appAttest": {
"required": true,
"environment": "production"
}
}Release the updated app
Publish the new version of your app that supports Wallet Attestation. This version uses the new client identifier and presents Wallet Attestation proofs to issuers that support it. Existing app versions continue to use the original client identifier and operate without attestation.
Retire the old client identifier
Once you are confident that enough users have migrated to the new app version, coordinate with the issuer to remove the old client identifier from their trusted wallet list. This completes the migration and ensures all active wallet instances use Wallet Attestation.
How would you rate this page?
Last updated on