Skip to main content

Tokenization

Azotte's tokenization system securely handles sensitive payment data by replacing it with non-sensitive tokens, ensuring PCI compliance and reducing security risks.

Token Overview

What is Tokenization?

Tokenization replaces sensitive payment information (like credit card numbers) with unique, non-sensitive tokens that can be safely stored and transmitted without security concerns.

Original Data: 4111111111111111 (Credit Card Number)
Token: tok_1A2B3C4D5E6F7G8H (Secure Token)

Token Types

  • Payment Method Tokens: Credit cards, bank accounts, digital wallets
  • Customer Tokens: Customer payment profile references
  • Session Tokens: Temporary tokens for payment sessions
  • Subscription Tokens: Recurring payment references

Token Lifecycle

Token Creation

// Client-side tokenization (secure)
const token = await azotte.createToken({
card: {
number: '4111111111111111',
exp_month: 12,
exp_year: 2025,
cvc: '123'
}
});

console.log(token.id); // tok_1A2B3C4D5E6F7G8H

Token Usage

// Use token for payments (server-side)
const payment = await azotte.payments.create({
amount: 2000,
currency: 'usd',
payment_method: token.id, // Use token instead of raw card data
customer: 'cus_123'
});

Token Expiration

interface Token {
id: string;
type: 'card' | 'bank_account' | 'wallet';
created: number;
expires: number; // Unix timestamp
used: boolean;
livemode: boolean;
metadata: Record<string, string>;
}

// Tokens have specific lifespans
const tokenLifespans = {
card: 3600, // 1 hour
bank_account: 7200, // 2 hours
session: 900, // 15 minutes
reusable: null // No expiration
};

Security Architecture

Tokenization Vault

┌─────────────────────┐     ┌──────────────────────┐     ┌─────────────────────┐
│ Client Application │────▶│ Tokenization Vault │────▶│ Payment Gateway │
│ │ │ │ │ │
│• Collects Card Data │ │• Encrypts PAN │ │• Processes Payments │
│• Receives Token │ │• Generates Token │ │• Uses Token │
│• Stores Token Only │ │• Stores Mapping │ │• Returns Results │
└─────────────────────┘ └──────────────────────┘ └─────────────────────┘

Encryption Standards

  • AES-256: Advanced Encryption Standard
  • RSA-2048: Public key cryptography
  • TLS 1.3: Transport layer security
  • HSM: Hardware Security Modules for key management

Key Management

interface TokenVaultSecurity {
encryption: {
algorithm: 'AES-256-GCM';
key_rotation: '90_days';
hsm_backed: true;
};
access_control: {
rbac: boolean;
multi_factor_auth: boolean;
audit_logging: boolean;
};
compliance: {
pci_dss_level: 1;
fips_140_2: 'level_3';
common_criteria: 'eal4+';
};
}

Client-Side Tokenization

JavaScript SDK

<!DOCTYPE html>
<html>
<head>
<script src="https://js.azotte.com/v3/azotte.js"></script>
</head>
<body>
<form id="card-form">
<div id="card-element">
<!-- Secure card input field -->
</div>
<button type="submit">Pay</button>
</form>

<script>
const azotte = Azotte('pk_live_...');
const elements = azotte.elements();

// Create secure card element
const cardElement = elements.create('card', {
style: {
base: {
fontSize: '16px',
color: '#424770'
}
}
});

cardElement.mount('#card-element');

// Handle form submission
document.getElementById('card-form').addEventListener('submit', async (e) => {
e.preventDefault();

const {token, error} = await azotte.createToken(cardElement);

if (error) {
console.error('Tokenization failed:', error.message);
} else {
// Send token to server
submitTokenToServer(token.id);
}
});

function submitTokenToServer(tokenId) {
fetch('/process-payment', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ token: tokenId })
});
}
</script>
</body>
</html>

Mobile SDK Integration

// iOS Swift example
import AzotteSDK

class PaymentViewController: UIViewController {
@IBOutlet weak var cardView: AZCardFormView!

func tokenizeCard() {
let cardParams = AZCardParams()
cardParams.number = "4111111111111111"
cardParams.expMonth = 12
cardParams.expYear = 2025
cardParams.cvc = "123"

AzotteAPI.shared.createToken(card: cardParams) { token, error in
if let token = token {
self.processPayment(with: token.tokenId)
} else {
self.handleError(error)
}
}
}
}

Server-Side Token Management

Token Validation

import azotte

def validate_token(token_id):
try:
token = azotte.Token.retrieve(token_id)

# Check if token is valid
if not token.used and token.expires > time.time():
return True
else:
return False
except azotte.error.InvalidRequestError:
return False

def process_payment(token_id, amount):
if not validate_token(token_id):
raise ValueError("Invalid or expired token")

payment = azotte.Payment.create(
amount=amount,
currency='usd',
payment_method=token_id
)

return payment

Token Reuse Policies

interface TokenReusePolicy {
single_use: boolean; // Token can only be used once
expiration_time: number; // Token lifetime in seconds
customer_scoped: boolean; // Token tied to specific customer
domain_restricted: boolean; // Token usage restricted by domain
}

// Configure token policies
const tokenPolicy: TokenReusePolicy = {
single_use: true,
expiration_time: 3600,
customer_scoped: true,
domain_restricted: false
};

Advanced Tokenization

Network Tokenization

// Apple Pay / Google Pay tokenization
interface NetworkToken {
type: 'apple_pay' | 'google_pay' | 'samsung_pay';
cryptogram: string;
eci: string; // Electronic Commerce Indicator
payment_data: {
version: string;
data: string;
signature: string;
header: {
ephemeralPublicKey: string;
publicKeyHash: string;
transactionId: string;
};
};
}

const processNetworkToken = async (networkToken: NetworkToken) => {
const token = await azotte.tokens.create({
type: 'network_token',
network_token: networkToken
});

return token;
};

Multi-Party Tokenization

// Marketplace tokenization for multi-party payments
const createMarketplaceToken = async (paymentData) => {
const token = await azotte.tokens.create({
card: paymentData.card,
marketplace: {
platform_id: 'platform_123',
connected_account: 'acct_456',
fee_percentage: 2.5
}
});

return token;
};

Compliance & Audit

PCI DSS Compliance

Through tokenization, merchants can reduce their PCI DSS scope:

Data ElementPre-TokenizationPost-Tokenization
Card NumbersIn ScopeOut of Scope
CVV/CVCIn ScopeOut of Scope
Cardholder DataIn ScopeOut of Scope
Transaction LogsIn ScopeReduced Scope

Audit Logging

interface TokenAuditLog {
event_id: string;
timestamp: string;
event_type: 'created' | 'used' | 'expired' | 'revoked';
token_id: string;
customer_id?: string;
metadata: {
ip_address: string;
user_agent: string;
request_id: string;
};
}

// Audit events are automatically logged
const auditEvents = await azotte.audit.listTokenEvents({
token_id: 'tok_123',
start_date: '2024-01-01',
end_date: '2024-01-31'
});

Performance Optimization

Token Caching

class TokenCache {
constructor() {
this.cache = new Map();
this.ttl = 3600; // 1 hour
}

set(key, token) {
this.cache.set(key, {
token,
expires: Date.now() + (this.ttl * 1000)
});
}

get(key) {
const cached = this.cache.get(key);
if (cached && cached.expires > Date.now()) {
return cached.token;
}

this.cache.delete(key);
return null;
}
}

// Usage
const tokenCache = new TokenCache();
const cacheKey = `customer_${customerId}_default`;

let token = tokenCache.get(cacheKey);
if (!token) {
token = await createNewToken(paymentMethod);
tokenCache.set(cacheKey, token);
}

Batch Tokenization

# Batch tokenize multiple payment methods
def batch_tokenize_cards(card_list):
tokens = []

for card_data in card_list:
try:
token = azotte.Token.create(card=card_data)
tokens.append(token)
except Exception as e:
tokens.append({'error': str(e)})

return tokens

# Usage
cards = [
{'number': '4111111111111111', 'exp_month': 12, 'exp_year': 2025},
{'number': '4000056655665556', 'exp_month': 6, 'exp_year': 2026}
]

tokens = batch_tokenize_cards(cards)

Error Handling

Common Token Errors

enum TokenErrorCode {
INVALID_CARD = 'invalid_card_number',
EXPIRED_CARD = 'expired_card',
INVALID_CVC = 'invalid_cvc',
TOKEN_EXPIRED = 'token_expired',
TOKEN_ALREADY_USED = 'token_already_used',
INSUFFICIENT_FUNDS = 'insufficient_funds'
}

interface TokenError {
code: TokenErrorCode;
message: string;
param?: string;
decline_code?: string;
}

Error Recovery

const handleTokenizationError = (error) => {
switch (error.code) {
case 'invalid_card_number':
showError('Please check your card number');
break;

case 'expired_card':
showError('Your card has expired');
break;

case 'invalid_cvc':
showError('Please check your security code');
break;

case 'token_expired':
// Automatically retry tokenization
retryTokenization();
break;

default:
showError('Payment method error. Please try again.');
}
};

Testing & Development

Test Token Data

const testCards = {
visa: '4242424242424242',
visa_debit: '4000056655665556',
mastercard: '5555555555554444',
amex: '378282246310005',
declined: '4000000000000002',
insufficient_funds: '4000000000009995',
expired: '4000000000000069'
};

// Create test tokens
const testToken = await azotte.tokens.create({
card: {
number: testCards.visa,
exp_month: 12,
exp_year: 2025,
cvc: '123'
}
});

Integration Testing

describe('Tokenization Service', () => {
it('should create valid token from card data', async () => {
const cardData = {
number: '4242424242424242',
exp_month: 12,
exp_year: 2025,
cvc: '123'
};

const token = await tokenService.createToken(cardData);

expect(token.id).toMatch(/^tok_/);
expect(token.used).toBe(false);
expect(token.card.last4).toBe('4242');
});

it('should reject expired tokens', async () => {
const expiredToken = 'tok_expired_123';

await expect(
paymentService.processPayment(expiredToken, 2000)
).rejects.toThrow('Token has expired');
});
});

Best Practices

Security Guidelines

  1. Never store raw card data - Always use tokens
  2. Validate tokens server-side - Don't trust client validation
  3. Use HTTPS everywhere - Encrypt all communications
  4. Implement token expiration - Limit token lifetime
  5. Log token usage - Maintain audit trails

Performance Tips

  1. Cache frequently used tokens - Reduce API calls
  2. Batch tokenization operations - Improve efficiency
  3. Use appropriate token types - Match use case requirements
  4. Monitor token usage patterns - Optimize based on data

Next Steps