Takaisin blogiin
Compliance

eIDAS 2.0: Digital Identity and the Future of Consent

GetCookies-tiimiOctober 18, 202513 min lukuaika
eIDASDigital IdentityEUConsent

TLDR: eIDAS 2.0 introduces the European Digital Identity Wallet with new consent requirements for identity attributes.

Read full summary

Guide to consent management under the updated eIDAS regulation. Covers selective disclosure of identity attributes, wallet-based consent flows, integration requirements for relying parties accepting EU digital identities, and the future of privacy-preserving identity verification.

Summary by Claude AI

What is eIDAS 2.0?

eIDAS 2.0 is the updated European electronic identification and trust services regulation that mandates every EU Member State provide citizens with a European Digital Identity Wallet (EUDI Wallet) by 2026. This wallet enables privacy-preserving identity verification through selective disclosure—users can prove specific attributes like "over 18" without revealing their full birthdate, fundamentally changing how consent works for identity data.

Introduction: The Digital Identity Revolution

The way we prove who we are online is about to fundamentally change. For decades, digital identity has meant sharing more information than necessary—providing your full birthdate just to prove you're an adult, or your complete address to verify your country of residence.

eIDAS 2.0 changes everything. By 2026, every EU citizen will have access to a digital wallet that puts them in complete control of their identity data. They'll choose exactly what to share, with whom, and for how long. And they'll have a cryptographic audit trail of every disclosure.

For organizations accepting identity verification—from online retailers to financial services—this represents the biggest shift in identity management since the internet began. The traditional model of collecting and storing identity data is giving way to a verification model where you confirm attributes without ever holding sensitive data.

This guide explores how eIDAS 2.0 transforms consent management and what organizations need to do to prepare for this identity revolution.

Understanding the EUDI Wallet Architecture

The European Digital Identity Wallet isn't just a digital ID card—it's a comprehensive identity management system built on privacy-preserving cryptography.

Core Components

// EUDI Wallet architecture overview
interface EUDIWalletArchitecture {
  // User-controlled identity wallet
  wallet: {
    holder: 'EU citizen or resident';
    storage: 'Device-based (smartphone/tablet)';
    control: 'User has full control over disclosures';
    interoperability: 'Cross-border by design';
  };

  // Verifiable credentials issued by trusted authorities
  credentials: {
    pid: 'Person Identification Data (core identity)';
    attestations: 'Additional verified attributes';
    qualifiedCertificates: 'QES, QSeals for signatures';
    pseudonyms: 'Privacy-preserving identifiers';
  };

  // Trust framework
  trust: {
    issuers: 'Government-approved credential issuers';
    verifiers: 'Relying parties accepting wallet credentials';
    trustLists: 'EU-maintained lists of trusted services';
    governance: 'eIDAS 2.0 regulation and technical specs';
  };
}

// Credential types in the EUDI Wallet
interface EUDICredentialTypes {
  // Person Identification Data - mandatory core identity
  pid: {
    familyName: string;
    firstName: string;
    dateOfBirth: string; // ISO 8601
    nationality: string; // ISO 3166-1 alpha-2
    uniqueIdentifier: string; // Pseudonymous
    issuingCountry: string;
    issuingAuthority: string;
    issuanceDate: string;
    expiryDate: string;
  };

  // Optional attestations
  attestations: {
    address?: AddressAttestation;
    drivingLicense?: DrivingLicenseAttestation;
    educationalCredentials?: EducationalAttestation;
    professionalQualifications?: ProfessionalAttestation;
    healthInsurance?: HealthInsuranceAttestation;
    ageVerification?: AgeVerificationAttestation;
  };

  // Derived credentials for privacy
  derivedCredentials: {
    ageProof: 'Boolean proof of age threshold';
    nationalityProof: 'Proof of EU/EEA citizenship';
    residencyProof: 'Proof of residence in specific country';
  };
}

The Selective Disclosure Revolution

The most transformative aspect of eIDAS 2.0 is selective disclosure—the ability to prove specific attributes without revealing underlying data:

// Selective disclosure implementation
class SelectiveDisclosureManager {
  private cryptoEngine: ZKProofEngine;
  private credentialStore: SecureCredentialStore;

  async createSelectiveDisclosure(
    request: DisclosureRequest,
    credentials: VerifiableCredential[]
  ): Promise<SelectiveDisclosurePresentation> {
    // Parse what the verifier is requesting
    const requestedAttributes = this.parseRequest(request);

    // Determine minimum disclosure needed
    const minimalDisclosure = this.calculateMinimalDisclosure(
      requestedAttributes,
      credentials
    );

    // Generate cryptographic proofs
    const proofs: AttributeProof[] = [];

    for (const attribute of minimalDisclosure) {
      if (attribute.type === 'exact_value') {
        // Reveal the actual value
        proofs.push({
          attribute: attribute.name,
          type: 'disclosed',
          value: attribute.value,
          proof: await this.cryptoEngine.createDisclosureProof(
            attribute,
            credentials
          )
        });
      } else if (attribute.type === 'range_proof') {
        // Prove value is within range without revealing it
        proofs.push({
          attribute: attribute.name,
          type: 'range_proof',
          statement: attribute.statement, // e.g., "age >= 18"
          proof: await this.cryptoEngine.createRangeProof(
            attribute,
            credentials
          )
        });
      } else if (attribute.type === 'membership_proof') {
        // Prove value is in a set without revealing which
        proofs.push({
          attribute: attribute.name,
          type: 'membership_proof',
          set: attribute.allowedValues, // e.g., EU countries
          proof: await this.cryptoEngine.createMembershipProof(
            attribute,
            credentials
          )
        });
      } else if (attribute.type === 'predicate_proof') {
        // Prove arbitrary predicate
        proofs.push({
          attribute: attribute.name,
          type: 'predicate_proof',
          predicate: attribute.predicate,
          proof: await this.cryptoEngine.createPredicateProof(
            attribute,
            credentials
          )
        });
      }
    }

    // Create presentation
    return {
      context: ['https://www.w3.org/2018/credentials/v1', 'https://eudi.ec.europa.eu/2024/wallet/v1'],
      type: ['VerifiablePresentation', 'EUDIWalletPresentation'],
      holder: this.generateHolderIdentifier(request.verifier),
      proofs,
      metadata: {
        created: new Date().toISOString(),
        verifierIdentity: request.verifier,
        purpose: request.purpose,
        expiresAt: this.calculateExpiry(request),
        consentReference: this.generateConsentReference()
      }
    };
  }

  private calculateMinimalDisclosure(
    requested: AttributeRequest[],
    credentials: VerifiableCredential[]
  ): MinimalDisclosure[] {
    const minimal: MinimalDisclosure[] = [];

    for (const req of requested) {
      // Always try to use privacy-preserving proofs first
      if (req.acceptsRangeProof && this.canCreateRangeProof(req, credentials)) {
        minimal.push({
          name: req.attribute,
          type: 'range_proof',
          statement: req.rangeStatement
        });
      } else if (req.acceptsMembershipProof && this.canCreateMembershipProof(req, credentials)) {
        minimal.push({
          name: req.attribute,
          type: 'membership_proof',
          allowedValues: req.membershipSet
        });
      } else if (req.acceptsPredicateProof && this.canCreatePredicateProof(req, credentials)) {
        minimal.push({
          name: req.attribute,
          type: 'predicate_proof',
          predicate: req.predicate
        });
      } else {
        // Fall back to exact disclosure only if necessary
        minimal.push({
          name: req.attribute,
          type: 'exact_value',
          value: this.getAttributeValue(req.attribute, credentials)
        });
      }
    }

    return minimal;
  }
}

Consent in the eIDAS 2.0 Era

eIDAS 2.0 fundamentally changes how consent works for identity data. Instead of blanket consent to data collection, users give granular, revocable consent for specific disclosures.

The New Consent Paradigm

// eIDAS 2.0 consent management
interface EIDASConsentModel {
  // Traditional cookie consent
  traditionalConsent: {
    model: 'Opt-in/opt-out';
    granularity: 'Category-based';
    storage: 'Website controls consent records';
    revocation: 'User requests, site processes';
    evidence: 'Consent management platform logs';
  };

  // eIDAS 2.0 identity consent
  eidasConsent: {
    model: 'Transaction-based disclosure';
    granularity: 'Attribute-level';
    storage: 'Wallet maintains consent records';
    revocation: 'User controls directly via wallet';
    evidence: 'Cryptographic proof in wallet';
  };
}

// Consent flow for identity verification
class EIDASConsentManager {
  private walletConnector: WalletConnectionService;
  private consentStore: ConsentRecordStore;
  private auditLogger: AuditLogService;

  async requestIdentityConsent(
    verificationRequest: VerificationRequest
  ): Promise<ConsentResult> {
    // Step 1: Generate consent request
    const consentRequest = this.createConsentRequest(verificationRequest);

    // Step 2: Present to user via wallet interface
    const userDecision = await this.presentConsentRequest(consentRequest);

    if (!userDecision.approved) {
      await this.auditLogger.log({
        event: 'consent_denied',
        request: consentRequest,
        reason: userDecision.reason,
        timestamp: new Date().toISOString()
      });

      return {
        success: false,
        reason: userDecision.reason,
        alternatives: this.suggestAlternatives(verificationRequest)
      };
    }

    // Step 3: Receive selective disclosure from wallet
    const disclosure = await this.walletConnector.receiveDisclosure(
      consentRequest.id,
      userDecision.approvedAttributes
    );

    // Step 4: Verify cryptographic proofs
    const verification = await this.verifyDisclosure(disclosure);

    if (!verification.valid) {
      throw new Error('Disclosure verification failed');
    }

    // Step 5: Store consent record (without storing the actual data)
    await this.consentStore.record({
      consentId: consentRequest.id,
      timestamp: new Date().toISOString(),
      verifier: verificationRequest.verifier,
      purpose: verificationRequest.purpose,
      attributesVerified: userDecision.approvedAttributes.map(a => a.name),
      // Note: We don't store the actual values, just proof we verified them
      proofReference: disclosure.proofReference,
      expiresAt: disclosure.metadata.expiresAt
    });

    // Step 6: Log for audit trail
    await this.auditLogger.log({
      event: 'consent_granted',
      consentId: consentRequest.id,
      attributes: userDecision.approvedAttributes.map(a => a.name),
      purpose: verificationRequest.purpose,
      timestamp: new Date().toISOString()
    });

    return {
      success: true,
      verification: verification.results,
      consentReference: consentRequest.id
    };
  }

  private createConsentRequest(
    verification: VerificationRequest
  ): ConsentRequest {
    return {
      id: this.generateRequestId(),
      verifier: {
        name: verification.verifier.name,
        identifier: verification.verifier.euTrustServiceId,
        trustMark: verification.verifier.trustMark,
        privacyPolicy: verification.verifier.privacyPolicyUrl
      },
      purpose: {
        description: verification.purpose.description,
        legalBasis: verification.purpose.legalBasis,
        retentionPeriod: verification.purpose.dataRetention
      },
      requestedAttributes: verification.attributes.map(attr => ({
        attribute: attr.name,
        required: attr.required,
        purpose: attr.specificPurpose,
        acceptsMinimalDisclosure: attr.acceptsZKProof
      })),
      created: new Date().toISOString(),
      expiresAt: new Date(Date.now() + 15 * 60 * 1000).toISOString() // 15 min
    };
  }

  async revokeConsent(consentId: string, userId: string): Promise<RevocationResult> {
    // Verify user owns this consent
    const consent = await this.consentStore.get(consentId);

    if (!consent) {
      throw new Error('Consent record not found');
    }

    // Mark consent as revoked
    await this.consentStore.revoke(consentId, {
      revokedAt: new Date().toISOString(),
      revokedBy: userId,
      reason: 'user_request'
    });

    // Notify verifier of revocation (if still within validity period)
    if (new Date(consent.expiresAt) > new Date()) {
      await this.notifyVerifierOfRevocation(consent);
    }

    // Log revocation
    await this.auditLogger.log({
      event: 'consent_revoked',
      consentId,
      timestamp: new Date().toISOString()
    });

    return {
      success: true,
      consentId,
      revokedAt: new Date().toISOString()
    };
  }
}

User-Controlled Consent Records

With eIDAS 2.0, users maintain their own consent records in their wallet:

// User's wallet consent management
class WalletConsentDashboard {
  private wallet: EUDIWallet;
  private consentHistory: ConsentHistoryStore;

  async getConsentHistory(filters?: ConsentFilters): Promise<ConsentRecord[]> {
    const records = await this.consentHistory.query({
      userId: this.wallet.holderId,
      ...filters
    });

    return records.map(record => ({
      id: record.id,
      verifier: {
        name: record.verifierName,
        trustLevel: record.verifierTrustLevel,
        logo: record.verifierLogo
      },
      timestamp: record.timestamp,
      purpose: record.purpose,
      attributesShared: record.disclosedAttributes,
      expiresAt: record.expiryDate,
      status: this.calculateStatus(record),
      actions: this.getAvailableActions(record)
    }));
  }

  async viewDisclosureDetails(consentId: string): Promise<DisclosureDetails> {
    const record = await this.consentHistory.get(consentId);

    return {
      overview: {
        verifier: record.verifierName,
        date: record.timestamp,
        purpose: record.purpose
      },
      attributesShared: record.disclosedAttributes.map(attr => ({
        name: attr.name,
        disclosureType: attr.type, // 'exact', 'range_proof', etc.
        valueShared: attr.type === 'exact' ? attr.value : null,
        proofStatement: attr.type !== 'exact' ? attr.statement : null
      })),
      consent: {
        legalBasis: record.legalBasis,
        retention: record.retentionPeriod,
        canRevoke: this.canRevoke(record)
      },
      audit: {
        proofReference: record.proofReference,
        blockchainAnchor: record.anchorReference,
        verificationTimestamp: record.verificationTimestamp
      }
    };
  }

  async exportConsentHistory(format: 'json' | 'pdf'): Promise<ExportedHistory> {
    const records = await this.getConsentHistory();

    if (format === 'json') {
      return {
        format: 'json',
        data: JSON.stringify(records, null, 2),
        filename: `consent-history-${Date.now()}.json`
      };
    }

    // Generate PDF report
    return {
      format: 'pdf',
      data: await this.generatePDFReport(records),
      filename: `consent-history-${Date.now()}.pdf`
    };
  }
}

Integrating with EUDI Wallets

For organizations that need to verify identity, integration with EUDI Wallets requires becoming a "Relying Party" in the eIDAS trust framework.

Relying Party Integration

// EUDI Wallet relying party integration
class EUDIRelyingParty {
  private config: RelyingPartyConfig;
  private trustFramework: TrustFrameworkClient;
  private verifier: PresentationVerifier;
  private sessionManager: SessionManager;

  constructor(config: RelyingPartyConfig) {
    this.config = config;
    this.trustFramework = new TrustFrameworkClient(config.trustListUrl);
    this.verifier = new PresentationVerifier(config.verifierKeyPair);
    this.sessionManager = new SessionManager();
  }

  async initiateVerification(
    requirements: VerificationRequirements
  ): Promise<VerificationSession> {
    // Step 1: Create verification request according to ARF specs
    const request = await this.createVerificationRequest(requirements);

    // Step 2: Create session
    const session = await this.sessionManager.create({
      requestId: request.id,
      requirements,
      status: 'pending',
      createdAt: new Date().toISOString(),
      expiresAt: new Date(Date.now() + 15 * 60 * 1000).toISOString()
    });

    // Step 3: Generate QR code or deep link for wallet connection
    const connectionMethod = await this.generateConnectionMethod(request);

    return {
      sessionId: session.id,
      request,
      connectionMethod,
      expiresAt: session.expiresAt
    };
  }

  private async createVerificationRequest(
    requirements: VerificationRequirements
  ): Promise<PresentationRequest> {
    // Follow OpenID4VP specification
    return {
      response_type: 'vp_token',
      client_id: this.config.clientId,
      redirect_uri: this.config.redirectUri,
      presentation_definition: {
        id: this.generateDefinitionId(),
        input_descriptors: requirements.attributes.map(attr => ({
          id: `${attr.name}_descriptor`,
          name: attr.displayName,
          purpose: attr.purpose,
          constraints: {
            fields: [{
              path: [`$.credentialSubject.${attr.name}`, `$.vc.credentialSubject.${attr.name}`],
              filter: attr.filter,
              predicate: attr.acceptsZKProof ? attr.predicate : undefined
            }]
          }
        })),
        format: {
          'jwt_vc': { alg: ['ES256'] },
          'ldp_vc': { proof_type: ['Ed25519Signature2018'] }
        }
      },
      nonce: this.generateNonce(),
      state: this.generateState()
    };
  }

  async processWalletResponse(
    response: WalletResponse
  ): Promise<VerificationResult> {
    // Step 1: Validate response structure
    this.validateResponseStructure(response);

    // Step 2: Verify presentation signature
    const signatureValid = await this.verifier.verifyPresentation(
      response.vp_token
    );

    if (!signatureValid) {
      throw new VerificationError('Invalid presentation signature');
    }

    // Step 3: Verify credential issuer is trusted
    const issuerTrusted = await this.trustFramework.verifyIssuer(
      response.credential.issuer
    );

    if (!issuerTrusted) {
      throw new VerificationError('Credential issuer not in trust list');
    }

    // Step 4: Verify credential is not revoked
    const revocationStatus = await this.checkRevocation(response.credential);

    if (revocationStatus.revoked) {
      throw new VerificationError('Credential has been revoked');
    }

    // Step 5: Verify cryptographic proofs (for selective disclosure)
    const proofsValid = await this.verifySelectiveDisclosureProofs(
      response.presentation
    );

    if (!proofsValid.allValid) {
      throw new VerificationError('Selective disclosure proof verification failed');
    }

    // Step 6: Extract verified attributes
    const verifiedAttributes = this.extractVerifiedAttributes(
      response.presentation,
      proofsValid.proofResults
    );

    return {
      success: true,
      sessionId: response.state,
      verifiedAttributes,
      issuer: response.credential.issuer,
      issuanceDate: response.credential.issuanceDate,
      proofType: this.determineProofType(response.presentation),
      timestamp: new Date().toISOString()
    };
  }

  private async verifySelectiveDisclosureProofs(
    presentation: VerifiablePresentation
  ): Promise<ProofVerificationResult> {
    const results: ProofResult[] = [];

    for (const proof of presentation.proofs) {
      let valid: boolean;
      let details: any;

      switch (proof.type) {
        case 'disclosed':
          // Verify the disclosed value matches the credential
          valid = await this.verifier.verifyDisclosedValue(proof);
          details = { value: proof.value };
          break;

        case 'range_proof':
          // Verify zero-knowledge range proof
          valid = await this.verifier.verifyRangeProof(
            proof.proof,
            proof.statement
          );
          details = { statement: proof.statement };
          break;

        case 'membership_proof':
          // Verify set membership proof
          valid = await this.verifier.verifyMembershipProof(
            proof.proof,
            proof.set
          );
          details = { set: proof.set };
          break;

        case 'predicate_proof':
          // Verify arbitrary predicate proof
          valid = await this.verifier.verifyPredicateProof(
            proof.proof,
            proof.predicate
          );
          details = { predicate: proof.predicate };
          break;

        default:
          valid = false;
          details = { error: 'Unknown proof type' };
      }

      results.push({
        attribute: proof.attribute,
        type: proof.type,
        valid,
        details
      });
    }

    return {
      allValid: results.every(r => r.valid),
      proofResults: results
    };
  }
}

Trust Framework Verification

// eIDAS trust framework client
class TrustFrameworkClient {
  private trustListUrl: string;
  private cachedTrustList: TrustList | null = null;
  private cacheExpiry: Date | null = null;

  constructor(trustListUrl: string) {
    this.trustListUrl = trustListUrl;
  }

  async verifyIssuer(issuerId: string): Promise<IssuerVerification> {
    const trustList = await this.getTrustList();

    const issuer = trustList.issuers.find(i => i.id === issuerId);

    if (!issuer) {
      return {
        trusted: false,
        reason: 'Issuer not found in trust list'
      };
    }

    // Verify issuer's qualification
    const qualificationValid = this.verifyQualification(issuer);

    if (!qualificationValid) {
      return {
        trusted: false,
        reason: 'Issuer qualification expired or invalid'
      };
    }

    return {
      trusted: true,
      issuer: {
        name: issuer.name,
        country: issuer.country,
        qualifications: issuer.qualifications,
        supervisoryBody: issuer.supervisoryBody
      }
    };
  }

  async verifyCredentialType(
    credentialType: string,
    issuerId: string
  ): Promise<CredentialTypeVerification> {
    const trustList = await this.getTrustList();

    const issuer = trustList.issuers.find(i => i.id === issuerId);

    if (!issuer) {
      return {
        authorized: false,
        reason: 'Issuer not found'
      };
    }

    const authorization = issuer.authorizedCredentialTypes.find(
      ct => ct.type === credentialType
    );

    if (!authorization) {
      return {
        authorized: false,
        reason: `Issuer not authorized to issue ${credentialType}`
      };
    }

    return {
      authorized: true,
      scope: authorization.scope,
      restrictions: authorization.restrictions
    };
  }

  private async getTrustList(): Promise<TrustList> {
    if (this.cachedTrustList && this.cacheExpiry && this.cacheExpiry > new Date()) {
      return this.cachedTrustList;
    }

    // Fetch and verify trust list
    const response = await fetch(this.trustListUrl);
    const trustList = await response.json();

    // Verify trust list signature
    const signatureValid = await this.verifyTrustListSignature(trustList);

    if (!signatureValid) {
      throw new Error('Trust list signature verification failed');
    }

    // Cache for 1 hour
    this.cachedTrustList = trustList;
    this.cacheExpiry = new Date(Date.now() + 60 * 60 * 1000);

    return trustList;
  }
}

Impact on Consent Management Platforms

eIDAS 2.0 will significantly impact traditional CMPs. Here's how to prepare:

Hybrid Consent Architecture

// Hybrid CMP supporting both cookie consent and EUDI Wallet
class HybridConsentManager {
  private cookieConsent: CookieConsentManager;
  private walletConsent: EUDIConsentManager;
  private unifiedPreferences: UnifiedPreferenceStore;

  async initializeConsent(context: ConsentContext): Promise<ConsentInterface> {
    // Determine which consent mechanisms apply
    const mechanisms = this.determineApplicableMechanisms(context);

    const interfaces: ConsentInterface[] = [];

    // Traditional cookie consent (still needed for cookies!)
    if (mechanisms.includes('cookie_consent')) {
      interfaces.push(await this.cookieConsent.initialize(context));
    }

    // EUDI Wallet consent (for identity verification)
    if (mechanisms.includes('wallet_consent') && context.requiresIdentityVerification) {
      interfaces.push(await this.walletConsent.initialize(context));
    }

    // Return unified interface
    return this.createUnifiedInterface(interfaces);
  }

  async handleConsentChoice(choice: UserConsentChoice): Promise<ConsentResult> {
    const results: ConsentResult[] = [];

    // Process cookie consent
    if (choice.cookiePreferences) {
      const cookieResult = await this.cookieConsent.processChoice(
        choice.cookiePreferences
      );
      results.push(cookieResult);
    }

    // Process wallet consent (triggered by verification requests)
    if (choice.walletDisclosure) {
      const walletResult = await this.walletConsent.processDisclosure(
        choice.walletDisclosure
      );
      results.push(walletResult);
    }

    // Sync to unified preferences
    await this.unifiedPreferences.update({
      userId: choice.userId,
      cookieConsent: choice.cookiePreferences,
      walletConsent: choice.walletDisclosure,
      lastUpdated: new Date().toISOString()
    });

    return this.aggregateResults(results);
  }

  async getUserConsentStatus(userId: string): Promise<UnifiedConsentStatus> {
    const [cookieStatus, walletStatus] = await Promise.all([
      this.cookieConsent.getStatus(userId),
      this.walletConsent.getStatus(userId)
    ]);

    return {
      cookies: {
        necessary: true,
        analytics: cookieStatus.analytics,
        marketing: cookieStatus.marketing,
        functional: cookieStatus.functional
      },
      wallet: {
        disclosureHistory: walletStatus.disclosureHistory,
        activeConsents: walletStatus.activeConsents,
        revokedConsents: walletStatus.revokedConsents
      },
      lastModified: Math.max(
        new Date(cookieStatus.lastModified).getTime(),
        new Date(walletStatus.lastModified).getTime()
      )
    };
  }
}

Preference Center Updates

// Updated preference center supporting EUDI Wallet
class ModernPreferenceCenter {
  async render(userId: string): Promise<PreferenceCenterUI> {
    const status = await this.getUnifiedStatus(userId);

    return {
      sections: [
        // Traditional cookie preferences
        {
          id: 'cookies',
          title: 'Cookie Preferences',
          description: 'Control how we use cookies and similar technologies',
          categories: [
            {
              id: 'necessary',
              name: 'Strictly Necessary',
              description: 'Required for the website to function',
              enabled: true,
              locked: true
            },
            {
              id: 'analytics',
              name: 'Analytics',
              description: 'Help us understand how you use our site',
              enabled: status.cookies.analytics,
              locked: false
            },
            {
              id: 'marketing',
              name: 'Marketing',
              description: 'Used to deliver relevant advertisements',
              enabled: status.cookies.marketing,
              locked: false
            }
          ]
        },

        // NEW: Identity verification history
        {
          id: 'identity',
          title: 'Identity Verification History',
          description: 'Your EUDI Wallet disclosure history with us',
          enabled: status.wallet.disclosureHistory.length > 0,
          items: status.wallet.disclosureHistory.map(d => ({
            id: d.id,
            date: d.timestamp,
            purpose: d.purpose,
            attributesShared: d.attributes,
            status: d.status,
            actions: d.status === 'active' ? ['view', 'revoke'] : ['view']
          }))
        },

        // NEW: Connected wallet status
        {
          id: 'wallet_connection',
          title: 'EUDI Wallet',
          description: 'Manage your digital identity wallet connection',
          connected: status.wallet.connected,
          walletInfo: status.wallet.connected ? {
            provider: status.wallet.providerName,
            lastUsed: status.wallet.lastUsed
          } : null,
          actions: status.wallet.connected
            ? ['disconnect', 'view_history']
            : ['connect']
        }
      ]
    };
  }
}

Implementation Timeline and Preparation

eIDAS 2.0 Rollout Timeline

Milestone Date Impact
Regulation adopted December 2024 Legal framework in place
Technical specifications finalized June 2025 Integration specs available
Pilot wallets launched December 2025 Early adopter testing
Mandatory wallet availability September 2026 All EU citizens can get wallet
Large platforms must accept September 2027 Mandatory relying party status
Full cross-border interoperability December 2027 Seamless EU-wide usage

Preparation Checklist for Organizations

// eIDAS 2.0 preparation checklist
const eidasPreparationChecklist = {
  phase1_assessment: {
    timeline: '2024-2025',
    tasks: [
      {
        task: 'Audit current identity verification needs',
        details: 'Identify all processes requiring identity verification',
        priority: 'high'
      },
      {
        task: 'Map data currently collected vs. needed',
        details: 'Identify opportunities for data minimization',
        priority: 'high'
      },
      {
        task: 'Assess CMP upgrade requirements',
        details: 'Evaluate if current CMP can support wallet integration',
        priority: 'medium'
      },
      {
        task: 'Legal review of consent processes',
        details: 'Ensure processes align with eIDAS requirements',
        priority: 'high'
      }
    ]
  },

  phase2_planning: {
    timeline: '2025',
    tasks: [
      {
        task: 'Architecture design for wallet integration',
        details: 'Design technical integration with EUDI Wallets',
        priority: 'high'
      },
      {
        task: 'Update privacy policies',
        details: 'Add wallet consent and selective disclosure explanations',
        priority: 'medium'
      },
      {
        task: 'Train staff on new consent model',
        details: 'Ensure teams understand wallet-based verification',
        priority: 'medium'
      },
      {
        task: 'Select wallet integration partners',
        details: 'Choose SDK/service providers for integration',
        priority: 'high'
      }
    ]
  },

  phase3_implementation: {
    timeline: '2025-2026',
    tasks: [
      {
        task: 'Implement relying party infrastructure',
        details: 'Set up verification endpoints and trust framework connection',
        priority: 'high'
      },
      {
        task: 'Develop hybrid consent interface',
        details: 'Build UI supporting both cookie and wallet consent',
        priority: 'high'
      },
      {
        task: 'Integrate with pilot wallets',
        details: 'Test with early wallet implementations',
        priority: 'medium'
      },
      {
        task: 'Update audit and compliance processes',
        details: 'Ensure compliance monitoring covers wallet interactions',
        priority: 'medium'
      }
    ]
  },

  phase4_launch: {
    timeline: '2026-2027',
    tasks: [
      {
        task: 'Launch wallet verification option',
        details: 'Offer users wallet-based verification',
        priority: 'high'
      },
      {
        task: 'Monitor user adoption',
        details: 'Track wallet usage vs. traditional methods',
        priority: 'medium'
      },
      {
        task: 'Optimize user experience',
        details: 'Refine flows based on user feedback',
        priority: 'medium'
      },
      {
        task: 'Achieve mandatory compliance',
        details: 'Ensure full compliance by deadline',
        priority: 'critical'
      }
    ]
  }
};

Frequently Asked Questions

Will eIDAS 2.0 replace cookie consent?

No. eIDAS 2.0 addresses identity verification, not website tracking. Cookie consent under GDPR/ePrivacy remains separate. However, the two may interact when identity verification is needed alongside website functionality that uses cookies.

Do all businesses need to support EUDI Wallets?

Large online platforms and certain regulated sectors (banking, government services) will have mandatory support requirements. Other businesses can choose whether to accept wallet-based verification. However, supporting wallets offers significant advantages for user trust and data minimization.

How does selective disclosure work technically?

Selective disclosure uses zero-knowledge proofs (ZKPs) and other cryptographic techniques. For example, to prove you're over 18, the wallet creates a mathematical proof that your birthdate makes you at least 18 years old, without revealing the actual date. The verifier can confirm the proof is valid without learning your birthdate.

What happens if a user loses their wallet device?

EUDI Wallets include recovery mechanisms. Users can backup their wallet to secure cloud storage or recovery devices. The wallet ecosystem includes standardized recovery procedures that allow credential re-issuance while maintaining security.

The Future: Privacy-Preserving Identity

eIDAS 2.0 and the EUDI Wallet represent a fundamental shift in digital identity and privacy. Instead of the current model where organizations collect and store identity data (with all associated risks), we're moving to a model where users prove attributes without sharing underlying data.

For consent management, this means:

  1. Less data to protect: You verify attributes without storing them
  2. User-controlled records: Users maintain their own consent history
  3. Cryptographic proof: Audit trails are mathematically verifiable
  4. True data minimization: Request only what you need, receive only proofs

Organizations that embrace this shift will benefit from reduced data liability, increased user trust, and alignment with the direction privacy regulation is heading globally.

The future of privacy isn't about managing ever-larger consent databases—it's about not needing that data in the first place. eIDAS 2.0 shows us how to get there.

Additional Resources

G

GetCookies-tiimi

Kirjoittanut ja ylläpitää GetCookies-tiimi, Getia AS, Oslo, Norja. Artikkeli on yleistä tietoa evästesuostumuksesta eikä oikeudellista neuvontaa.

Skannaa oma sivustosi ilmaiseksi

Ilmaispaketissa banneri toimii yhdellä sivustolla ja saat kolme evästeskannausta kuukaudessa. Ei korttia, ei myyntipuheluita.