For the complete documentation index, see llms.txt. This page is also available as Markdown.

EUDI Developer Guide: Secure EUDI Wallet Integration for Mobile Developers (ARF, DCQL, 2026-2027)

Secure your EUDI Wallet integration. Don't let a stolen credential from a compromised device pass every cryptographic check—close the ARF spec security gaps with mobile runtime protection SDK.

You're building a mobile app that accepts EU digital identity credentials. The user taps "Login with EU Wallet." Their EUDI Wallet presents a signed credential, and your backend verifies it. Simple protocol, but the mobile runtime around it is an attack surface the ARF spec doesn't cover. Let's be honest: trying to protect this cryptographic perfection from post-install rooting and Frida hooks is the exact reason mobile security engineers drink so much coffee. This guide shows how to ensure security of the full flow with Talsec app protection tools: RASP+ SDK & AppiCrypt.

This multi-part series is built for CTOs, architects, and mobile developers. We break down the regulatory clock, the architectural shifts, and the hands-on implementation details required to close the mobile security gap.

Explore the complete series:

Disclaimer for full transparency: This article utilizes Talsec technology. We know we aren't the only vendor in the mobile security space. But we are the one running on 2,000,000,000 devices. We’ve protected more apps than there are cars on Earth. It's safe to say we know what we're doing.

Architecture

Your app is a Relying Party (RP): you request credentials from the user's EUDI Wallet using OpenID4VP, receive signed SD-JWT presentations, and verify them offline against the EU Trusted Lists. The credential was signed by an EU Member State issuer; your backend never calls home to that issuer during verification.

That offline verification model is powerful, but it creates a gap: a stolen credential from a compromised device passes every cryptographic check. The ARF spec defines the credential format and protocol, but won't resolve the runtime device security for you. That gap is yours to close.

The Talsec security layer closes it by adding runtime proofs to every presentation flow, app authenticity and runtime integrity, before you ever parse the credential.

Step 1: Request Credentials (DCQL Query)

Use DCQL (the current OpenID4VP 1.0 query format) to specify exactly what you need. Request minimum attributes; this is a GDPR requirement.

For age verification only, request just age_over_18, the wallet that proves the claim without revealing the birth date.

Step 2: Secure the Client Request

Before calling the EUDI Wallet, your app generates an AppiCrypt® token (cryptogram) and attaches it to the request. As it's mentioned here, the cryptogram is a "cryptographical snapshot" of the device's security state, verified on the backend in real time to detect threats such as debuggers or simulators, and it proves the app binary is genuine and not repackaged.

Let's see some sample codes to understand a bit better the pattern, start with Android (Kotlin):

Similarly we can repeat that for iOS (Swift):

What the cryptogram token gives your backend:

  • App authenticity: A repackaged or cloned APK/IPA cannot produce a valid cryptogram for your App ID (AppiCrypt docs)

  • Runtime threat flags: root/jailbreak (su, Magisk, palera1n), hooking frameworks (Frida/Xposed), emulators, debuggers, all captured in the same cryptogram

  • Real-time risk score: the backend script verifies the cryptogram and returns an integrity status per request

For on-device runtime protection, use freeRASP (open-source) or RASP+, which adds overlay detection, screen-mirroring defense, and accessibility-abuse monitoring.

Device Risk State API: Talsec also offers a server-side Device Risk State API, a product that lets your backend check a device's security state on-demand, independent of the user's current app session. See plans comparison or contact Talsec directly for access and API details.

Step 3: Verify on the Server

When the mobile app sends a SecureRequest, your backend runs several checks before reading any credential claims.

The ordering matters: cheap checks first, expensive ones last. Here is how you can create your gates in each step in your framework of choice for the backend:

  1. App authenticity (AppiCrypt® backend script) verification: Decrypt and verify the AppiCrypt cryptogram using the simple script Talsec provides. The cryptogram is bound to your App instance, and the request payload, a repackaged or cloned APK/IPA, cannot produce a valid one. REJECT 403 if invalid.

  2. Runtime integrity (RASP flags inside the cryptogram): The AppiCrypt cryptogram also carries RASP threat flags captured on the device. Check: no root/jailbreak, no hooking framework (Frida/Xposed/Substrate), no debugger, no emulator. Tune the policy per your risk appetite. REJECT 403 if flags exceed policy threshold.

  1. Credential verification (ARF-compliant, any OpenID4VP library)

    • Issuer key must chain to the EU Trusted List (offline, no issuer callback)

    • nonce must match what you sent (prevents presentation replay)

    • aud must match your RP Client ID (prevents cross-RP reuse)

    • key-binding JWT must be valid (proves wallet holds the key) → REJECT 403 if any check fails

  2. Revocation Check (Token Status List / OCSP): Fetch the Token Status List bitstring from the issuer CDN. Confirm the credential's index is 0 (active). REJECT 403 if revoked.

Here is what it looks like in a simplified image:

Privacy & Operational Rules

I find some gaps when working with EUDI wallets, and I thought to bring them here. Three rules that prevent production incidents and GDPR fines:

1. Check credential revocation (Token Status List): Every SD-JWT contains a status claim pointing to a Token Status List. Fetch it, decode the bitstring, and confirm the credential index is still 0 (active). This is the most commonly skipped verification step; without it, you'll accept revoked credentials indefinitely.

2. Never log the raw vp_token: The verifiable presentation contains disclosed PII (name, birth date, nationality). Logging it raw = GDPR Article 5 violation. Log only: issuer, vct, iat, exp, and your internal session ID. If you need the payload for debugging, store it encrypted with a short TTL in a separate audit store.

3. Use pairwise identifiers for user storage: Don't store the wallet's sub claim directly; it's the same across all RPs the user interacts with, enabling cross-service tracking. Instead, derive a per-RP identifier:

Integration Checklist

Use this as your PR/release todolist. Every item maps to a security control described above; skip one, and you have a gap.

  • Register as RP in the Member State trust ecosystem

  • Integrate Talsec SDK, AppiCrypt + RASP+ (Android / iOS platforms)

  • Backend: verify AppiCrypt cryptogram on every sensitive request (covers app authenticity + RASP threat flags in one step)

  • Build DCQL queries, minimum attributes per use case

  • Verify SD-JWT: issuer signature → disclosure hashes → KB-JWT (nonce + aud + sd_hash)

  • Check credential revocation via Token Status List on every presentation

  • Fetch and cache EU Trusted Lists; validate issuer cert chain

  • Define risk policy: fail-closed on AppiCrypt violation, step-up on borderline scores

  • Per-request nonce bound to your RP client_id

  • Never log raw vp_token, log only metadata (issuer, vct, iat, session ID)

  • Store pairwise-derived user IDs, not raw wallet sub claims

Conclusion

The EUDI Wallet shifts identity verification from server-mediated flows to cryptographic offline verification. That's powerful, but it moves the trust boundary to the mobile device. If the device is compromised, the credential is compromised. Start with the checklist above. Ship iteratively: RASP+ first, then upgrade to AppiCrypt and Malware Detection as your threat exposure grows. Happy coding!

written by Majid Hajian

Last updated

Was this helpful?