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 Element | Pre-Tokenization | Post-Tokenization |
|---|---|---|
| Card Numbers | In Scope | Out of Scope |
| CVV/CVC | In Scope | Out of Scope |
| Cardholder Data | In Scope | Out of Scope |
| Transaction Logs | In Scope | Reduced 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
- Never store raw card data - Always use tokens
- Validate tokens server-side - Don't trust client validation
- Use HTTPS everywhere - Encrypt all communications
- Implement token expiration - Limit token lifetime
- Log token usage - Maintain audit trails
Performance Tips
- Cache frequently used tokens - Reduce API calls
- Batch tokenization operations - Improve efficiency
- Use appropriate token types - Match use case requirements
- Monitor token usage patterns - Optimize based on data
Next Steps
- Learn about Encryption
- Understand Data Protection
- Explore PCI Compliance