Skip to content
advanced Phase 89 · Payment Deep Dive

3DS and Tokenization

3D Secure flow, card tokenization, PCI compliance patterns

45m
0 problems
Topic Progress 0%

3D Secure Flow

3DS Authentication Flow

  Customer          Store            Payment Gateway      Issuer
    │                 │                    │                │
    │  1. Checkout    │                    │                │
    ├────────────────►│                    │                │
    │                 │  2. Create 3DS     │                │
    │                 ├───────────────────►│                │
    │                 │  3. Return auth    │                │
    │                 │◄───────────────────┤                │
    │  4. Redirect    │                    │                │
    │◄────────────────┤                    │                │
    │  5. 3DS Page    │                    │                │
    │─────────────────┼────────────────────┼───────────────►│
    │  6. Challenge   │                    │                │
    │◄────────────────┼────────────────────┼───────────────┤
    │  7. Result      │                    │                │
    │─────────────────┼───────────────────►│                │
    │                 │  8. Verify         │                │
    │                 ├───────────────────►│                │
    │                 │  9. Auth result    │                │
    │                 │◄───────────────────┤                │

3DS Service

namespace Vendor\Payment\Service\ThreeDS;

class ThreeDsService
{
    private ThreeDsGatewayInterface $gateway;

    public function initiate(
        OrderInterface $order,
        CardDataInterface $card
    ): ThreeDsResult {
        $response = $this->gateway->createAuthentication(new ThreeDsRequest([
            'amount' => $order->getGrandTotal(),
            'currency' => $order->getCurrencyCode(),
            'card_number' => $card->getNumber(),
            'card_expiry' => $card->getExpiry(),
            'cardholder_name' => $card->getHolderName(),
            'order_id' => $order->getIncrementId(),
            'return_url' => $this->getReturnUrl(),
        ]));

        return new ThreeDsResult([
            'status' => $response->getStatus(),
            'acs_url' => $response->getAcsUrl(),
            'pareq' => $response->getPaReq(),
            'md' => $response->getMd(),
            'requires_challenge' => $response->requiresChallenge(),
        ]);
    }

    public function validate(string $pareSponse, string $md): ThreeDsValidationResult
    {
        $response = $this->gateway->validateAuthentication(new ValidateRequest([
            'pareq_response' => $pareSponse,
            'md' => $md,
        ]));

        return new ThreeDsValidationResult([
            'authenticated' => $response->isAuthenticated(),
            'eci' => $response->getEci(),
            'cavv' => $response->getCavv(),
            'xid' => $response->getXid(),
        ]);
    }
}

Card Tokenization

Tokenization Architecture

  Frontend (Client)    Payment Gateway    Vault (Encrypted)
       │                     │                   │
  1. Card data         │                   │
  ├─────────────────►  │                   │
       │  2. Token       │                   │
       │◄────────────────┤                   │
       │  3. Store token │                   │
       │                 ├──────────────────►│
       │                 │                   │

Token Vault

namespace Vendor\Payment\Model\Vault;

class TokenVault
{
    private TokenRepositoryInterface $tokenRepo;
    private EncryptorInterface $encryptor;

    public function store(
        CustomerInterface $customer,
        TokenDataInterface $tokenData
    ): TokenInterface {
        // Tokenize card via gateway
        $gatewayToken = $this->gateway->tokenize(new TokenizeRequest([
            'card_number' => $tokenData->getCardNumber(),
            'card_expiry' => $tokenData->getExpiry(),
            'cardholder_name' => $tokenData->getHolderName(),
        ]));

        // Store only non-sensitive data
        $token = new TokenData([
            'customer_id' => $customer->getId(),
            'gateway_token' => $gatewayToken->getToken(),
            'card_type' => $gatewayToken->getCardType(),
            'card_last_four' => $gatewayToken->getLastFour(),
            'card_expiry' => $gatewayToken->getExpiry(),
            'is_active' => true,
        ]);

        return $this->tokenRepo->save($token);
    }

    public function charge(
        TokenInterface $token,
        float $amount,
        string $currency
    ): PaymentResult {
        return $this->gateway->charge(new ChargeRequest([
            'token' => $token->getGatewayToken(),
            'amount' => $amount,
            'currency' => $currency,
        ]));
    }
}

PCI Compliance

namespace Vendor\Payment\Security\Pci;

class PciComplianceManager
{
    public function sanitizeCardData(array $data): array
    {
        // Never store raw card numbers
        unset($data['card_number']);
        unset($data['cvv']);

        // Mask card number for display
        if (isset($data['card_last_four'])) {
            $data['card_display'] = '**** **** **** ' . $data['card_last_four'];
        }

        return $data;
    }

    public function validateStorage(array $storageConfig): ComplianceResult
    {
        $errors = [];

        if ($storageConfig['encrypt_card_data'] !== true) {
            $errors[] = 'Card data must be encrypted at rest';
        }

        if ($storageConfig['tokenize'] !== true) {
            $errors[] = 'Card data must be tokenized';
        }

        if ($storageConfig['log_card_data'] === true) {
            $errors[] = 'Raw card data must never be logged';
        }

        return new ComplianceResult(
            empty($errors),
            $errors
        );
    }
}

3DS Frictionless Flow

Frictionless Authentication

namespace Vendor\Payment\Service\ThreeDS;

class FrictionlessHandler
{
    public function handle(ThreeDsResult $result): bool
    {
        // Check if issuer supported frictionless flow
        if ($result->isFrictionless()) {
            // No challenge required - proceed with payment
            $this->logger->info('3DS frictionless authentication', [
                'eci' => $result->getEci(),
                'score' => $result->getAuthenticationScore(),
            ]);
            return true;
        }

        // Challenge required - redirect to ACS
        return false;
    }
}

3DS Result Handling

namespace Vendor\Payment\Service\ThreeDS;

class ThreeDsResultHandler
{
    public function processResult(
        ThreeDsValidationResult $result,
        OrderInterface $order
    ): void {
        $payment = $order->getPayment();

        if ($result->isAuthenticated()) {
            // Store 3DS data for liability shift
            $payment->setAdditionalInformation('3ds_eci', $result->getEci());
            $payment->setAdditionalInformation('3ds_cavv', $result->getCavv());
            $payment->setAdditionalInformation('3ds_xid', $result->getXid());
            $payment->setAdditionalInformation('3ds_authenticated', true);

            // Proceed with authorization
            $this->authService->authorize($order, $payment);
        } else {
            // 3DS failed - decline or retry
            $order->setState(Order::STATE_CANCELED);
            $order->addCommentToStatusHistory(
                '3D Secure authentication failed'
            );
        }
    }
}

Token Management

Token Lifecycle

namespace Vendor\Payment\Model\Vault;

class TokenLifecycle
{
    public function onCardExpiry(TokenInterface $token): void
    {
        // Notify customer
        $this->notificationService->send(
            $token->getCustomerId(),
            'Your saved card ending in ' . $token->getLastFour() . ' has expired'
        );

        // Deactivate token
        $token->setIsActive(false);
        $this->tokenRepo->save($token);
    }

    public function onDelete(TokenInterface $token): void
    {
        // Remove from gateway
        $this->gateway->deleteToken($token->getGatewayToken());

        // Remove from vault
        $this->tokenRepo->delete($token);
    }
}

Token Security

namespace Vendor\Payment\Security\Token;

class TokenSecurity
{
    public function validateTokenAccess(
        TokenInterface $token,
        CustomerInterface $customer
    ): bool {
        // Only token owner can use it
        if ($token->getCustomerId() !== $customer->getId()) {
            return false;
        }

        // Check token is active
        if (!$token->isActive()) {
            return false;
        }

        // Check expiry
        if ($this->isExpired($token)) {
            return false;
        }

        return true;
    }
}

Quiz

1. What is 3D Secure?

Question 1 options

2. What is card tokenization?

Question 2 options

3. What does PCI compliance require?

Question 3 options

Flashcards

Question

What is 3D Secure?

Answer

Cardholder authentication for fraud prevention

Question

What is tokenization?

Answer

Replacing card data with a non-sensitive token

Question

What is ECI in 3DS?

Answer

Electronic Commerce Indicator - authentication level

Question

What does liability shift mean?

Answer

Fraud liability moves from merchant to issuer after 3DS

Revision Notes

Key Takeaways

  • 1. 3D Secure adds authentication layer for card payments
  • 2. Frictionless flow completes without customer challenge
  • 3. Tokenization replaces card data with reusable tokens
  • 4. PCI compliance requires never storing raw card numbers
  • 5. 3DS provides liability shift from merchant to issuer

Interview Tips

  • Explain the 3DS authentication flow steps
  • Discuss frictionless vs challenge authentication
  • Describe tokenization security benefits
  • Talk about PCI compliance requirements

Cheat Sheet

3D Secure:
  Frictionless → auto-approved (low risk)
  Challenge → customer authenticates (high risk)
  ECI → authentication level (05=full, 06=attempted)
  CAVV → cardholder authentication value

Tokenization:
  Store token (not card)
  Token → gateway → charge
  No raw card data in DB

PCI Compliance:
  Never store raw card numbers
  Never log CVV
  Encrypt sensitive data
  Use tokenization