import crypto from 'crypto'; import https from 'https'; import fs from 'fs'; // Read .env.local manually const envContent = fs.readFileSync('.env.local', 'utf8'); const env = {}; envContent.split('\n').forEach(line => { const match = line.match(/^([^=]+)=(.*)$/); if (match) { let val = match[2].trim(); if (val.startsWith('"') && val.endsWith('"')) { val = val.slice(1, -1); } env[match[1].trim()] = val; } }); const CLIENT_ID = env.APPLE_SEARCH_ADS_CLIENT_ID; const TEAM_ID = env.APPLE_SEARCH_ADS_TEAM_ID; const KEY_ID = env.APPLE_SEARCH_ADS_KEY_ID; const PRIVATE_KEY = env.APPLE_SEARCH_ADS_PRIVATE_KEY; function generateClientSecret() { if (!PRIVATE_KEY || PRIVATE_KEY.trim() === '') { throw new Error("APPLE_SEARCH_ADS_PRIVATE_KEY ist nicht in .env.local gesetzt!"); } const header = { alg: "ES256", kid: KEY_ID, typ: "JWT" }; const now = Math.floor(Date.now() / 1000); const payload = { sub: CLIENT_ID, aud: "https://appleid.apple.com", iat: now, exp: now + 86400 * 180, // 180 Tage iss: TEAM_ID }; const base64Header = Buffer.from(JSON.stringify(header)).toString("base64url"); const base64Payload = Buffer.from(JSON.stringify(payload)).toString("base64url"); const signingInput = `${base64Header}.${base64Payload}`; const signer = crypto.createSign("SHA256"); signer.update(signingInput); const formattedKey = PRIVATE_KEY.replace(/\\n/g, '\n'); const signature = signer.sign({ key: formattedKey, dsaEncoding: 'ieee-p1363' }, "base64url"); return `${signingInput}.${signature}`; } async function getAccessToken(clientSecret) { return new Promise((resolve, reject) => { const postData = new URLSearchParams({ grant_type: 'client_credentials', client_id: CLIENT_ID, client_secret: clientSecret, scope: 'searchadsorg' }).toString(); const options = { hostname: 'appleid.apple.com', port: 443, path: '/auth/oauth2/token', method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Content-Length': Buffer.byteLength(postData), 'User-Agent': 'Mozilla/5.0' } }; const req = https.request(options, (res) => { let data = ''; res.on('data', chunk => data += chunk); res.on('end', () => { try { resolve(JSON.parse(data)); } catch (e) { reject(new Error(`Parse error: ${data}`)); } }); }); req.on('error', reject); req.write(postData); req.end(); }); } async function main() { try { console.log("1. Generiere Client Secret (JWT)..."); const clientSecret = generateClientSecret(); console.log("Client Secret erfolgreich generiert."); console.log("2. Fordere Access Token bei Apple OAuth an..."); const tokenData = await getAccessToken(clientSecret); console.log("Antwort von Apple:", tokenData); } catch (err) { console.error("Fehler:", err.message); } } main();