const AUTHENTIK_URL = process.env.AUTHENTIK_URL || 'http://localhost:9000'; const CLIENT_ID = process.env.CLIENT_ID || 'kaboot-spa'; const CLIENT_SECRET = process.env.CLIENT_SECRET || ''; const USERNAME = process.env.TEST_USERNAME || ''; const PASSWORD = process.env.TEST_PASSWORD || ''; async function getTokenWithClientSecret(): Promise { if (!CLIENT_SECRET) throw new Error('CLIENT_SECRET not set'); const tokenUrl = `${AUTHENTIK_URL}/application/o/token/`; const params = new URLSearchParams({ grant_type: 'client_credentials', client_id: CLIENT_ID, client_secret: CLIENT_SECRET, scope: 'openid profile email', }); console.log(` Trying client_credentials with client_secret...`); const response = await fetch(tokenUrl, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: params.toString(), }); if (!response.ok) { const error = await response.text(); throw new Error(`${response.status} - ${error}`); } const data = await response.json(); return data.access_token; } async function getTokenWithServiceAccount(): Promise { if (!USERNAME || !PASSWORD) throw new Error('USERNAME and PASSWORD not set'); const tokenUrl = `${AUTHENTIK_URL}/application/o/token/`; const params = new URLSearchParams({ grant_type: 'password', client_id: CLIENT_ID, username: USERNAME, password: PASSWORD, scope: 'openid profile email', }); console.log(` Trying password grant with username/password...`); const response = await fetch(tokenUrl, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: params.toString(), }); if (!response.ok) { const error = await response.text(); throw new Error(`${response.status} - ${error}`); } const data = await response.json(); return data.access_token; } async function main() { console.log('Kaboot API Token Generator'); console.log('==========================\n'); console.log(`Authentik URL: ${AUTHENTIK_URL}`); console.log(`Client ID: ${CLIENT_ID}`); console.log(''); let token: string | null = null; if (CLIENT_SECRET) { try { token = await getTokenWithClientSecret(); console.log(' ✓ Success!\n'); } catch (error) { console.log(` ✗ Failed: ${error instanceof Error ? error.message : error}\n`); } } if (!token && USERNAME && PASSWORD) { try { token = await getTokenWithServiceAccount(); console.log(' ✓ Success!\n'); } catch (error) { console.log(` ✗ Failed: ${error instanceof Error ? error.message : error}\n`); } } if (token) { console.log('=== ACCESS TOKEN ==='); console.log(token); console.log('\n=== FOR .env.test ==='); console.log(`TEST_TOKEN=${token}`); return; } console.log('=== SETUP INSTRUCTIONS ===\n'); console.log('Method 1: Client Secret (Recommended for testing)\n'); console.log(' 1. Go to Authentik Admin: http://localhost:9000/if/admin/'); console.log(' 2. Navigate to: Applications → Providers → Kaboot OAuth2'); console.log(' 3. Change "Client type" from "Public" to "Confidential"'); console.log(' 4. Copy the "Client Secret" value'); console.log(' 5. Add to server/.env.test:'); console.log(' CLIENT_SECRET=\n'); console.log('Method 2: Service Account + App Password\n'); console.log(' 1. Go to Authentik Admin: http://localhost:9000/if/admin/'); console.log(' 2. Navigate to: Directory → Users'); console.log(' 3. Click "Create Service Account"'); console.log(' 4. Name it (e.g., "kaboot-test")'); console.log(' 5. After creation, click on the user → "App passwords" tab'); console.log(' 6. Create a new app password, copy the token'); console.log(' 7. Bind the service account to Kaboot app:'); console.log(' Applications → Kaboot → Policy/Group/User Bindings → Bind existing user'); console.log(' 8. Add to server/.env.test:'); console.log(' TEST_USERNAME='); console.log(' TEST_PASSWORD=\n'); process.exit(1); } main();