Created
October 7, 2024 17:39
-
-
Save felixguerrero12/8ff9f144b932a4b3d80711e0ef756be8 to your computer and use it in GitHub Desktop.
deviceCodeAuth.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // deviceCodeAuth.js | |
| import { showNotification } from '../modules/uiHelpers.js'; | |
| import { fetchPostRequest } from '../modules/api.js'; | |
| import { storeToken } from './insertToken.js'; | |
| let isDeviceCodeAuthInProgress = false; | |
| export function initializeDeviceCodeAuth() { | |
| const form = document.getElementById('deviceCodeAuthForm'); | |
| if (form) { | |
| form.addEventListener('submit', handleDeviceCodeAuth); | |
| } | |
| const cancelButton = document.getElementById('cancelDeviceCodeAuth'); | |
| if (cancelButton) { | |
| cancelButton.addEventListener('click', cancelDeviceCodeAuth); | |
| } | |
| // New code for handling custom client ID | |
| const clientIdSelect = document.getElementById('clientIdSelect'); | |
| const customClientIdGroup = document.getElementById('customClientIdGroup'); | |
| const customClientIdInput = document.getElementById('customClientId'); | |
| if (clientIdSelect && customClientIdGroup && customClientIdInput) { | |
| clientIdSelect.addEventListener('change', function() { | |
| if (this.value === 'custom') { | |
| customClientIdGroup.style.display = 'block'; | |
| customClientIdInput.setAttribute('required', 'required'); | |
| } else { | |
| customClientIdGroup.style.display = 'none'; | |
| customClientIdInput.removeAttribute('required'); | |
| } | |
| }); | |
| } | |
| } | |
| export function handleDeviceCodeAuth(e) { | |
| e.preventDefault(); | |
| if (isDeviceCodeAuthInProgress) { | |
| console.log('Device Code Auth already in progress'); | |
| return; | |
| } | |
| isDeviceCodeAuthInProgress = true; | |
| const clientIdSelect = document.getElementById('clientIdSelect'); | |
| const customClientIdInput = document.getElementById('customClientId'); | |
| let clientId = clientIdSelect.value; | |
| if (clientId === 'custom') { | |
| clientId = customClientIdInput.value; | |
| } | |
| const tenant = document.getElementById('deviceCodeTenant').value || 'common'; | |
| const scope = document.getElementById('deviceCodeScope').value; | |
| startDeviceCodeAuth(clientId, tenant, scope) | |
| .finally(() => { | |
| isDeviceCodeAuthInProgress = false; | |
| }); | |
| } | |
| export function startDeviceCodeAuth(clientId, tenant, scope) { | |
| return fetchPostRequest('/device_code_auth', { client_id: clientId, tenant, scope }) | |
| .then(data => { | |
| if (data.error) { | |
| throw new Error(data.error); | |
| } | |
| displayDeviceCodeInfo(data); | |
| return pollForToken(clientId, data.device_code, tenant, data.interval); | |
| }) | |
| .catch(error => { | |
| showNotification(`Error: ${error.message}`, 'error'); | |
| closeDeviceCodeAuthModal(); | |
| }); | |
| } | |
| function displayDeviceCodeInfo(data) { | |
| const resultElement = document.getElementById('deviceCodeResult'); | |
| resultElement.style.display = 'block'; | |
| const messageElement = document.getElementById('deviceCodeMessage'); | |
| const userCodeElement = document.getElementById('deviceCodeUserCode'); | |
| // Create clickable URL | |
| const url = 'https://microsoft.com/devicelogin'; | |
| messageElement.innerHTML = data.message.replace(url, `<a href="${url}" target="_blank">${url}</a>`); | |
| userCodeElement.innerHTML = `User Code: ${data.user_code} <button class="btn btn-sm btn-secondary ms-2" onclick="copyDeviceCode('${data.user_code}')">Copy</button>`; | |
| document.getElementById('cancelDeviceCodeAuth').style.display = 'inline-block'; | |
| } | |
| function copyDeviceCode(code) { | |
| navigator.clipboard.writeText(code).then(() => { | |
| showNotification('Device code copied to clipboard', 'success'); | |
| }).catch(err => { | |
| console.error('Failed to copy: ', err); | |
| showNotification('Failed to copy device code', 'error'); | |
| }); | |
| } | |
| // Make sure to expose the copyDeviceCode function globally | |
| window.copyDeviceCode = copyDeviceCode; | |
| let pollInterval = null; | |
| let shouldStopPolling = false; | |
| function pollForToken(clientId, deviceCode, tenant, interval) { | |
| return new Promise((resolve, reject) => { | |
| shouldStopPolling = false; | |
| pollInterval = setInterval(() => { | |
| if (shouldStopPolling) { | |
| clearInterval(pollInterval); | |
| return; | |
| } | |
| fetchPostRequest('/poll_for_token', { client_id: clientId, device_code: deviceCode, tenant }) | |
| .then(data => { | |
| if (data.status === 'success') { | |
| clearInterval(pollInterval); | |
| storeToken(data.access_token, 'access_token', tenant, null, 'Device Code') | |
| .then(() => { | |
| if (data.refresh_token) { | |
| return storeToken(data.refresh_token, 'refresh_token', tenant, null, 'Device Code Flow'); | |
| } | |
| }) | |
| .then(() => { | |
| showNotification(data.message, 'success'); | |
| resetDeviceCodeUI(); | |
| closeDeviceCodeAuthModal(); | |
| }) | |
| .catch(error => { | |
| console.error('Error storing token:', error); | |
| showNotification('Error storing token', 'error'); | |
| resetDeviceCodeUI(); | |
| closeDeviceCodeAuthModal(); | |
| }); | |
| } else if (data.status === 'error') { | |
| clearInterval(pollInterval); | |
| showNotification(`Error: ${data.message}`, 'error'); | |
| resetDeviceCodeUI(); | |
| closeDeviceCodeAuthModal(); | |
| reject(new Error(data.message)); | |
| } | |
| }) | |
| .catch(error => { | |
| clearInterval(pollInterval); | |
| showNotification(`Error: ${error.message}`, 'error'); | |
| resetDeviceCodeUI(); | |
| closeDeviceCodeAuthModal(); | |
| reject(error); | |
| }); | |
| }, interval * 1000); | |
| }); | |
| } | |
| function cancelDeviceCodeAuth() { | |
| isDeviceCodeAuthInProgress = false; | |
| shouldStopPolling = true; | |
| if (pollInterval) { | |
| clearInterval(pollInterval); | |
| } | |
| resetDeviceCodeUI(); | |
| showNotification('Device code authentication cancelled', 'info'); | |
| closeDeviceCodeAuthModal(); | |
| } | |
| function cleanup() { | |
| shouldStopPolling = true; | |
| if (pollInterval) { | |
| clearInterval(pollInterval); | |
| } | |
| } | |
| function resetDeviceCodeUI() { | |
| document.getElementById('deviceCodeResult').style.display = 'none'; | |
| document.getElementById('deviceCodeMessage').textContent = ''; | |
| document.getElementById('deviceCodeUserCode').textContent = ''; | |
| document.getElementById('cancelDeviceCodeAuth').style.display = 'none'; | |
| } | |
| function closeDeviceCodeAuthModal() { | |
| console.log('Attempting to close device code auth modal'); | |
| const modal = document.getElementById('deviceCodeAuthModal'); | |
| if (modal) { | |
| // Try Bootstrap 5 approach | |
| const bootstrapModal = bootstrap.Modal.getInstance(modal); | |
| if (bootstrapModal) { | |
| bootstrapModal.hide(); | |
| } else { | |
| console.log('Bootstrap modal instance not found, trying alternative methods'); | |
| } | |
| // Try Bootstrap 4 approach (if you're using Bootstrap 4) | |
| if (typeof $ !== 'undefined' && typeof $.fn.modal !== 'undefined') { | |
| $(modal).modal('hide'); | |
| } | |
| // Fallback: remove modal classes and backdrop | |
| modal.classList.remove('show'); | |
| modal.style.display = 'none'; | |
| document.body.classList.remove('modal-open'); | |
| const backdrop = document.querySelector('.modal-backdrop'); | |
| if (backdrop) { | |
| backdrop.remove(); | |
| } | |
| } else { | |
| console.error('Modal element not found'); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment