(function() { const crossClientInput = document.getElementById("cross_client_input"); const crossClientList = document.getElementById("cross-client-list"); const addClientBtn = document.getElementById("add-cross-client"); const scopesList = document.getElementById("scopes-list"); const customScopeInput = document.getElementById("custom_scope_input"); const addCustomScopeBtn = document.getElementById("add-custom-scope"); // Default scopes that should be checked by default const defaultScopes = ["openid", "profile", "email", "offline_access"]; // Check default scopes on page load document.addEventListener("DOMContentLoaded", function() { const checkboxes = scopesList.querySelectorAll('input[type="checkbox"]'); checkboxes.forEach(cb => { if (defaultScopes.includes(cb.value)) { cb.checked = true; } }); }); function addCrossClient(value) { const trimmed = value.trim(); if (!trimmed) return; const chip = document.createElement("div"); chip.className = "chip"; const text = document.createElement("span"); text.textContent = trimmed; const hidden = document.createElement("input"); hidden.type = "hidden"; hidden.name = "cross_client"; hidden.value = trimmed; const remove = document.createElement("button"); remove.type = "button"; remove.textContent = "×"; remove.onclick = () => crossClientList.removeChild(chip); chip.append(text, hidden, remove); crossClientList.appendChild(chip); } function addCustomScope(scope) { const trimmed = scope.trim(); if (!trimmed || !scopesList) return; // Check if scope already exists const existingCheckboxes = scopesList.querySelectorAll('input[type="checkbox"]'); for (const cb of existingCheckboxes) { if (cb.value === trimmed) { cb.checked = true; return; } } // Add new scope checkbox const scopeItem = document.createElement("div"); scopeItem.className = "scope-item"; const checkbox = document.createElement("input"); checkbox.type = "checkbox"; checkbox.name = "extra_scopes"; checkbox.value = trimmed; checkbox.id = "scope_custom_" + trimmed; checkbox.checked = true; const label = document.createElement("label"); label.htmlFor = checkbox.id; label.textContent = trimmed; scopeItem.append(checkbox, label); scopesList.appendChild(scopeItem); } addClientBtn?.addEventListener("click", () => { addCrossClient(crossClientInput.value); crossClientInput.value = ""; crossClientInput.focus(); }); crossClientInput?.addEventListener("keydown", (e) => { if (e.key === "Enter") { e.preventDefault(); addCrossClient(crossClientInput.value); crossClientInput.value = ""; } }); addCustomScopeBtn?.addEventListener("click", () => { addCustomScope(customScopeInput.value); customScopeInput.value = ""; customScopeInput.focus(); }); customScopeInput?.addEventListener("keydown", (e) => { if (e.key === "Enter") { e.preventDefault(); addCustomScope(customScopeInput.value); customScopeInput.value = ""; } }); // Device Grant Login Handler const deviceGrantBtn = document.getElementById("device-grant-btn"); deviceGrantBtn?.addEventListener("click", async () => { deviceGrantBtn.disabled = true; deviceGrantBtn.textContent = "Loading..."; try { // Collect form data similar to regular login const form = document.getElementById("login-form"); const formData = new FormData(form); // Get selected scopes const scopes = formData.getAll("extra_scopes"); // Get cross-client values const crossClients = formData.getAll("cross_client"); // Get connector_id if specified const connectorId = formData.get("connector_id") || ""; // Initiate device flow with options const response = await fetch('/device/login', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ scopes: scopes, cross_clients: crossClients, connector_id: connectorId }) }); if (response.ok) { // Redirect to device flow page window.location.href = '/device'; } else { const errorText = await response.text(); alert('Failed to start device flow: ' + errorText); } } catch (error) { alert('Error starting device flow: ' + error.message); } finally { deviceGrantBtn.disabled = false; deviceGrantBtn.textContent = "Device Code Flow"; } }); })();