@warriorteam/redai-zalo-sdk
Version:
Comprehensive TypeScript/JavaScript SDK for Zalo APIs - Official Account, ZNS, Consultation Service, Group Messaging, and Social APIs
180 lines (142 loc) • 5.89 kB
text/typescript
/**
* Example: Official Account Authentication with PKCE
* Demonstrates how to use the updated createOAAuthUrl method with PKCE support
*/
import { ZaloSDK } from '../src';
// Initialize SDK
const sdk = new ZaloSDK({
appId: 'your_app_id',
appSecret: 'your_app_secret',
});
// Example 1: Basic OA Auth without PKCE
async function basicOAAuth() {
console.log('=== Basic OA Auth (without PKCE) ===');
const redirectUri = 'https://your-app.com/callback';
// Create auth URL - state will be auto-generated with 'zalo_oa_' prefix
const authResult = sdk.auth.createOAAuthUrl(redirectUri);
console.log('Authorization URL:', authResult.url);
console.log('Generated State:', authResult.state);
// You can also provide custom state
const customAuthResult = sdk.auth.createOAAuthUrl(redirectUri, 'my_custom_state');
console.log('Custom State URL:', customAuthResult.url);
console.log('Custom State:', customAuthResult.state);
}
// Example 2: OA Auth with PKCE for enhanced security (Manual PKCE)
async function oaAuthWithPKCE() {
console.log('\n=== OA Auth with Manual PKCE ===');
const redirectUri = 'https://your-app.com/callback';
// Step 1: Generate PKCE configuration
const pkce = sdk.auth.generatePKCE();
console.log('Generated PKCE:');
console.log('- Code Verifier:', pkce.code_verifier);
console.log('- Code Challenge:', pkce.code_challenge);
console.log('- Challenge Method:', pkce.code_challenge_method);
// Step 2: Create auth URL with manual PKCE
const authResult = sdk.auth.createOAAuthUrl(redirectUri, undefined, pkce, true);
console.log('\nAuthorization URL with PKCE:', authResult.url);
console.log('Generated State:', authResult.state);
console.log('Used PKCE:', authResult.pkce);
// IMPORTANT: Store the code_verifier and state for later use
// You'll need these when exchanging the authorization code for access token
console.log('\n⚠️ IMPORTANT: Store these values for token exchange:');
console.log('- Code Verifier:', pkce.code_verifier);
console.log('- State:', authResult.state);
return { pkce, state: authResult.state };
}
// Example 2b: OA Auth with Auto-Generated PKCE
async function oaAuthWithAutoPKCE() {
console.log('\n=== OA Auth with Auto-Generated PKCE ===');
const redirectUri = 'https://your-app.com/callback';
// Create auth URL with auto-generated PKCE (pkce=undefined, usePkce=true)
const authResult = sdk.auth.createOAAuthUrl(redirectUri, undefined, undefined, true);
console.log('Authorization URL with Auto PKCE:', authResult.url);
console.log('Generated State:', authResult.state);
console.log('Auto-Generated PKCE:', authResult.pkce);
// IMPORTANT: Store the auto-generated PKCE and state
console.log('\n⚠️ IMPORTANT: Store these auto-generated values:');
console.log('- Code Verifier:', authResult.pkce?.code_verifier);
console.log('- State:', authResult.state);
return authResult;
}
// Example 3: Complete flow - Authorization + Token Exchange
async function completeOAFlow() {
console.log('\n=== Complete OA Flow with PKCE ===');
const redirectUri = 'https://your-app.com/callback';
// Step 1: Generate PKCE and create auth URL
const pkce = sdk.auth.generatePKCE();
const authResult = sdk.auth.createOAAuthUrl(redirectUri, 'my_oa_flow', pkce);
console.log('1. Redirect user to:', authResult.url);
console.log('2. Store state and code_verifier:', {
state: authResult.state,
code_verifier: pkce.code_verifier
});
// Step 2: After user authorizes and returns with code
// (This would happen in your callback handler)
const simulateCallback = async (authorizationCode: string, returnedState: string) => {
console.log('\n3. User returned with authorization code');
// Verify state matches
if (returnedState !== authResult.state) {
throw new Error('State mismatch - possible CSRF attack');
}
// Step 3: Exchange code for access token with PKCE
try {
const tokenResult = await sdk.auth.getOAAccessToken({
app_id: 'your_app_id',
app_secret: 'your_app_secret',
code: authorizationCode,
redirect_uri: redirectUri,
code_verifier: pkce.code_verifier, // Include code_verifier for PKCE
});
console.log('4. Successfully obtained access token:', {
access_token: tokenResult.access_token.substring(0, 20) + '...',
expires_in: tokenResult.expires_in,
has_refresh_token: !!tokenResult.refresh_token
});
return tokenResult;
} catch (error) {
console.error('Failed to exchange code for token:', error);
throw error;
}
};
// Simulate the callback (in real app, this would be handled by your callback endpoint)
console.log('\n--- Simulating callback ---');
// await simulateCallback('simulated_auth_code', authResult.state);
}
// Example 4: Using getAuthUrls method
async function getAuthUrlsExample() {
console.log('\n=== Get Auth URLs ===');
const redirectUri = 'https://your-app.com/callback';
const pkce = sdk.auth.generatePKCE();
const authUrls = sdk.auth.getAuthUrls(redirectUri, pkce);
console.log('All auth URLs:', {
oa_auth_url: authUrls.oa_auth_url,
social_auth_url: authUrls.social_auth_url,
token_url: authUrls.token_url,
refresh_url: authUrls.refresh_url
});
}
// Run examples
async function runExamples() {
try {
await basicOAAuth();
await oaAuthWithPKCE();
await oaAuthWithAutoPKCE();
await completeOAFlow();
await getAuthUrlsExample();
} catch (error) {
console.error('Example error:', error);
}
}
// Export for use in other files
export {
basicOAAuth,
oaAuthWithPKCE,
oaAuthWithAutoPKCE,
completeOAFlow,
getAuthUrlsExample,
runExamples
};
// Run if this file is executed directly
if (require.main === module) {
runExamples();
}