Appearance
Table of Contents
- Overview
- Authentication Methods
- JWT Token Authentication
- API Key Authentication
- Wallet Signature Authentication
- Security Best Practices
- Troubleshooting
Overview
Pocketbook API supports three authentication methods, each designed for different use cases:
| Method | Best For | Expiry | Scopes |
|---|---|---|---|
| JWT Token | Web apps, user sessions | 24 hours | User-based permissions |
| API Key | Server-to-server, automation | No expiry* | Configurable scopes |
| Wallet Signature | One-time auth, Web3 apps | 5 minutes** | N/A (exchanges for JWT) |
* Can be revoked manually ** Timestamp window for signature validation
Authentication Methods
Quick Comparison
javascript
// JWT Token Authentication
fetch('/api/certificate/create', {
headers: {
'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIs...',
'Content-Type': 'application/json'
}
});
// API Key Authentication
fetch('/api/bulk-mint', {
headers: {
'x-api-key': 'pk_0000000000000000000000000000000000000000000000000000000000000001',
'Content-Type': 'application/json'
}
});
// Wallet Signature Authentication (initial auth)
fetch('/api/auth', {
method: 'POST',
body: JSON.stringify({
signature: '0x...',
address: '0x...',
message: 'Authenticate with Pocketbook: 1234567890',
timestamp: '1234567890'
})
});JWT Token Authentication
Overview
JSON Web Tokens (JWT) provide secure, stateless authentication for user sessions. Best suited for:
- Web applications
- Mobile apps
- User-specific operations
- Short-lived sessions
Getting a JWT Token
Step 1: Prepare Authentication Message
javascript
const timestamp = Math.floor(Date.now() / 1000);
const message = `Authenticate with Pocketbook: ${timestamp}`;Message Format: Must exactly match Authenticate with Pocketbook: <unix_timestamp>
Step 2: Sign Message with Wallet
javascript
// Using ethers.js v6
import { ethers } from 'ethers';
const provider = new ethers.BrowserProvider(window.ethereum);
const signer = await provider.getSigner();
const signature = await signer.signMessage(message);
const address = await signer.getAddress();javascript
// Using ethers.js v5
const provider = new ethers.providers.Web3Provider(window.ethereum);
const signer = provider.getSigner();
const signature = await signer.signMessage(message);
const address = await signer.getAddress();javascript
// Using viem
import { createWalletClient, custom } from 'viem';
import { mainnet } from 'viem/chains';
const client = createWalletClient({
chain: mainnet,
transport: custom(window.ethereum)
});
const [address] = await client.getAddresses();
const signature = await client.signMessage({
account: address,
message
});Step 3: Exchange Signature for JWT
javascript
const response = await fetch('https://api.pocketbook.studio/api/certificate/auth', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
signature,
address,
message,
timestamp: timestamp.toString()
})
});
const data = await response.json();
if (data.success) {
const token = data.data.token;
// Store token securely
localStorage.setItem('pocketbook_token', token);
}Using JWT Token
javascript
const token = localStorage.getItem('pocketbook_token');
const response = await fetch('https://api.pocketbook.studio/api/profile', {
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
}
});Token Structure
JWT tokens contain three parts separated by dots:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJ1c2VySWQiOiI2MjdhNjE3YjRjMWYyZDAwMDEiLCJlbWFpbCI6InVzZXJAZXhhbXBsZS5jb20iLCJyb2xlIjoidXNlciIsImlhdCI6MTY0MDk5NTIwMCwiZXhwIjoxNjQxMDgxNjAwfQ.
5J6k8hK3...
Header.Payload.SignatureDecoded Payload:
json
{
"userId": "507f1f77bcf86cd799439011",
"email": "user@example.com",
"role": "user",
"walletAddress": "0x1234...",
"smartAccountAddress": "0x5678...",
"enterpriseId": "ent_abc123",
"iat": 1640995200,
"exp": 1641081600
}Token Refresh
Tokens expire after 24 hours. Implement token refresh:
javascript
class AuthManager {
constructor() {
this.token = null;
this.expiresAt = null;
}
async authenticate(wallet) {
const timestamp = Math.floor(Date.now() / 1000);
const message = `Authenticate with Pocketbook: ${timestamp}`;
const signature = await wallet.signMessage(message);
const address = await wallet.getAddress();
const response = await fetch('/api/certificate/auth', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ signature, address, message, timestamp: timestamp.toString() })
});
const data = await response.json();
if (data.success) {
this.token = data.data.token;
const decoded = this.decodeJWT(this.token);
this.expiresAt = decoded.exp * 1000;
return this.token;
}
throw new Error('Authentication failed');
}
async getToken(wallet) {
// Check if token exists and is not expired
if (this.token && this.expiresAt > Date.now() + 300000) { // 5 min buffer
return this.token;
}
// Token expired or doesn't exist, re-authenticate
return await this.authenticate(wallet);
}
decodeJWT(token) {
const base64Url = token.split('.')[1];
const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
return JSON.parse(atob(base64));
}
}
// Usage
const authManager = new AuthManager();
const token = await authManager.getToken(wallet);API Key Authentication
Overview
API keys provide long-lived authentication for server-side integrations. Best suited for:
- Backend services
- Automated workflows
- CI/CD pipelines
- Third-party integrations
Creating an API Key
Via Dashboard
- Log in to your enterprise account at pocketbook.studio
- Navigate to Settings → API Keys
- Click Create New API Key
- Configure:
- Name: Descriptive name for the key
- Scopes: Select required permissions
- Rate Limit: Optional custom limit
- Copy and securely store the key (shown only once)
Via API
javascript
const response = await fetch('https://api.pocketbook.studio/api/enterprise/api-keys', {
method: 'POST',
headers: {
'Authorization': `Bearer ${jwtToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: 'Production Backend Key',
scopes: ['bulk:mint', 'voucher:create', 'certificate:read'],
rateLimit: 1000 // requests per hour
})
});
const data = await response.json();
const apiKey = data.data.apiKey.fullKey; // pk_00000...Using API Keys
javascript
const apiKey = process.env.POCKETBOOK_API_KEY; // Store in environment variables
const response = await fetch('https://api.pocketbook.studio/api/bulk-mint', {
method: 'POST',
headers: {
'x-api-key': apiKey,
'Content-Type': 'application/json'
},
body: JSON.stringify({
// ... request body
})
});API Key Scopes
| Scope | Description | Endpoints |
|---|---|---|
bulk:mint | Create bulk mint jobs | POST /bulk-mint |
bulk:retry | Retry bulk mint jobs | POST /bulk-mint/:id/retry |
bulk:read | Read bulk mint jobs | GET /bulk-mint, GET /bulk-mint/:id |
voucher:create | Create vouchers | POST /voucher/create |
voucher:read | Read voucher details | GET /voucher/:id |
voucher:regenerate | Regenerate vouchers | POST /voucher/:id/regenerate |
certificate:read | Read certificates | GET /certificate/:id |
certificate:create | Create certificates | POST /certificate/create |
analytics:read | Read analytics | GET /dashboard/, GET /reporting/ |
pos:voucher | POS voucher operations | Special POS endpoints |
Wallet Signature Authentication
Overview
Wallet signature authentication is a one-time authentication method that exchanges a signed message for a JWT token.
Authentication Flow
javascript
async function authenticateWithWallet(wallet) {
// 1. Generate timestamp and message
const timestamp = Math.floor(Date.now() / 1000);
const message = `Authenticate with Pocketbook: ${timestamp}`;
// 2. Sign message
const signature = await wallet.signMessage(message);
const address = await wallet.getAddress();
// 3. Submit to API
const response = await fetch('https://api.pocketbook.studio/api/auth', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
signature,
address,
message,
timestamp: timestamp.toString()
})
});
const data = await response.json();
if (!data.success) {
throw new Error(data.error || 'Authentication failed');
}
return data.data.token;
}Security Best Practices
API Key Security
✅ DO:
- Store API keys in environment variables
- Use different keys for development and production
- Rotate keys regularly
- Implement key rotation without downtime
- Use scoped keys with minimal permissions
- Monitor key usage for anomalies
- Revoke compromised keys immediately
❌ DON'T:
- Commit keys to version control
- Share keys via email or chat
- Use production keys in development
- Grant unnecessary scopes
- Embed keys in client-side code
- Reuse keys across projects
JWT Token Security
✅ DO:
- Store tokens securely (httpOnly cookies for web, secure storage for mobile)
- Implement token refresh before expiry
- Clear tokens on logout
- Validate token expiry on client side
- Use HTTPS for all API requests
❌ DON'T:
- Store tokens in localStorage if handling sensitive data
- Share tokens between users
- Ignore token expiry
- Include tokens in URLs
- Log tokens in analytics
Troubleshooting
Common Issues
"Invalid signature"
Cause: Signature doesn't match message or address
Solutions:
- Verify message format exactly matches:
Authenticate with Pocketbook: <timestamp> - Ensure timestamp is current (within 5 minutes)
- Check that address matches signing wallet
- Confirm wallet is properly connected
"Token expired"
Cause: JWT token has exceeded 24-hour lifetime
Solution: Re-authenticate to get new token
javascript
async function ensureValidToken(authManager, wallet) {
try {
return await authManager.getToken();
} catch (error) {
if (error.message.includes('expired')) {
return await authManager.authenticate(wallet);
}
throw error;
}
}"API key not found"
Cause: Invalid or revoked API key
Solutions:
- Verify key format:
pk_followed by 64 hex characters - Check key hasn't been revoked
- Ensure key is from correct environment (dev/prod)
- Regenerate key if needed
"Insufficient permissions"
Cause: API key lacks required scopes or user role insufficient
Solutions:
- Check API key scopes match endpoint requirements
- Update key with necessary scopes
- For JWT: ensure user has required role (enterprise, admin)
Need Help?
- Email: seth@pocketbook.studio
- Discord: Join our community
- Documentation: docs.pocketbook.studio
