UNPKG

vodia-teams

Version:

Microsoft Teams Direct Routing configuration tool

272 lines (232 loc) 8.69 kB
// auth.js - Authentication and app registration module const fs = require('fs'); const path = require('path'); const axios = require('axios'); const readline = require('readline'); // Function to authenticate with device code and create app registration async function authenticateWithDeviceCode(outputFile) { // Create readline interface for user input const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); // Function to prompt user function prompt(question) { return new Promise(resolve => { rl.question(question, answer => { resolve(answer); }); }); } try { console.log('=== Microsoft 365 Tenant Automation - Setup ==='); console.log('This script will authenticate and create necessary app registrations\n'); // Step 1: Initiate device code flow using Microsoft's public client ID console.log('Step 1: Initiating device code authentication...'); const deviceCodeResponse = await axios.post( 'https://login.microsoftonline.com/organizations/oauth2/v2.0/devicecode', new URLSearchParams({ client_id: '04b07795-8ddb-461a-bbee-02f9e1bf7b46', // Microsoft's Azure CLI client ID scope: 'https://graph.microsoft.com/.default offline_access' }).toString(), { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } } ); const { device_code, user_code, verification_uri, expires_in, interval } = deviceCodeResponse.data; console.log('\nTo sign in, use a web browser to open the page:', verification_uri); console.log('Enter the code', user_code, 'to authenticate'); console.log('NOTE: You must sign in with a Global Administrator account\n'); // Step 2: Poll for token console.log('Waiting for authentication...'); let tokenReceived = false; let accessToken = null; let tenantId = null; let attempts = Math.floor(expires_in / interval); while (!tokenReceived && attempts > 0) { try { await new Promise(resolve => setTimeout(resolve, interval * 1000)); const tokenResponse = await axios.post( 'https://login.microsoftonline.com/organizations/oauth2/v2.0/token', new URLSearchParams({ grant_type: 'urn:ietf:params:oauth:grant-type:device_code', device_code: device_code, client_id: '04b07795-8ddb-461a-bbee-02f9e1bf7b46' }).toString(), { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } } ); accessToken = tokenResponse.data.access_token; tokenReceived = true; console.log('Authentication successful!\n'); } catch (error) { if (error.response && error.response.data && error.response.data.error === 'authorization_pending') { attempts--; console.log('Waiting for you to complete authentication...'); continue; } throw error; } } if (!tokenReceived) { throw new Error('Authentication timed out. Please try again.'); } // Step 3: Get tenant details console.log('Step 2: Getting tenant details...'); const orgResponse = await axios.get( 'https://graph.microsoft.com/v1.0/organization', { headers: { 'Authorization': `Bearer ${accessToken}` } } ); tenantId = orgResponse.data.value[0].id; const tenantName = orgResponse.data.value[0].displayName; console.log(`Tenant identified: ${tenantName} (${tenantId})\n`); // Step 4: Create application registration console.log('Step 3: Creating application registration...'); const appName = `VodiaTeamsAutomation-${new Date().getTime()}`; const appRegistration = { displayName: appName, signInAudience: "AzureADMyOrg", requiredResourceAccess: [ { resourceAppId: "00000003-0000-0000-c000-000000000000", // Microsoft Graph resourceAccess: [ { id: "741f803b-c850-494e-b5df-cde7c675a1ca", // User.ReadWrite.All type: "Role" }, { id: "19dbc75e-c2e2-444c-a770-ec69d8559fc7", // Directory.ReadWrite.All type: "Role" }, { id: "7ab1d382-f21e-4acd-a863-ba3e13f7da61", // Directory.Read.All type: "Role" }, { id: "df021288-bdef-4463-88db-98f22de89214", // User.Read.All type: "Role" }, { id: "292d869f-3427-49a8-9dab-8c70152b74e9", // Organization.ReadWrite.All type: "Role" }, { id: "7e05723c-0bb0-42da-be95-ae9f08a6e53c", // Domain.ReadWrite.All type: "Role" }, { id: "bdd80a03-d9bc-451d-b7c4-ce7c63fe3c8f", // TeamSettings.ReadWrite.All type: "Role" }, { id: "0121dc95-1b9f-4aed-8bac-58c5ac466691", // TeamMember.ReadWrite.All type: "Role" } ] } ], web: { redirectUris: [ "https://login.microsoftonline.com/common/oauth2/nativeclient", "http://localhost" ], implicitGrantSettings: { enableIdTokenIssuance: false, enableAccessTokenIssuance: false } } }; // Create the application const appResponse = await axios.post( 'https://graph.microsoft.com/v1.0/applications', appRegistration, { headers: { 'Authorization': `Bearer ${accessToken}`, 'Content-Type': 'application/json' } } ); const appId = appResponse.data.appId; const appObjectId = appResponse.data.id; console.log(`Application created: ${appName}`); console.log(`Application (client) ID: ${appId}`); console.log(`Application Object ID: ${appObjectId}`); // Step 5: Create client secret console.log('\nStep 4: Creating client secret...'); const secretResponse = await axios.post( `https://graph.microsoft.com/v1.0/applications/${appObjectId}/addPassword`, { passwordCredential: { displayName: "Auto-generated Secret", endDateTime: "2027-12-31T00:00:00Z" } }, { headers: { 'Authorization': `Bearer ${accessToken}`, 'Content-Type': 'application/json' } } ); const clientSecret = secretResponse.data.secretText; // Step 6: Create service principal console.log('Step 5: Creating service principal...'); const spResponse = await axios.post( 'https://graph.microsoft.com/v1.0/servicePrincipals', { appId: appId }, { headers: { 'Authorization': `Bearer ${accessToken}`, 'Content-Type': 'application/json' } } ); console.log(`Service principal created: ${spResponse.data.id}`); // Step 7: Save credentials to file const credentials = { tenantId: tenantId, clientId: appId, clientSecret: clientSecret, appObjectId: appObjectId }; // Create directory for output file if it doesn't exist const outputDir = path.dirname(outputFile); if (outputDir && outputDir !== '.' && !fs.existsSync(outputDir)) { fs.mkdirSync(outputDir, { recursive: true }); } fs.writeFileSync(outputFile, JSON.stringify(credentials, null, 2)); console.log(`\nCredentials saved to ${outputFile}`); console.log('\nIMPORTANT: Keep this file secure as it contains sensitive information.'); // Step 8: Generate admin consent URL const adminConsentUrl = `https://login.microsoftonline.com/${tenantId}/adminconsent?client_id=${appId}&redirect_uri=http://localhost`; console.log('\nFinal Step: Please open the following URL in your browser to grant admin consent:'); console.log(adminConsentUrl); console.log('\nAfter granting consent, you can use the credentials in the saved file for API calls.'); await prompt('\nPress Enter to continue...'); rl.close(); return { success: true, tenantId: tenantId, clientId: appId, clientSecret: clientSecret, outputFile: outputFile }; } catch (error) { console.error('Error:', error.response?.data || error.message); rl.close(); throw error; } } module.exports = { authenticateWithDeviceCode };