<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Authorize - UniFi MCP Server</title>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
}
.container {
background: white;
border-radius: 16px;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
max-width: 420px;
width: 100%;
padding: 40px;
}
.logo {
text-align: center;
margin-bottom: 30px;
}
.logo svg {
width: 64px;
height: 64px;
fill: #0069ff;
}
.logo h1 {
font-size: 24px;
color: #1a1a2e;
margin-top: 12px;
}
.client-info {
background: #f8f9fa;
border-radius: 8px;
padding: 16px;
margin-bottom: 24px;
}
.client-info h2 {
font-size: 14px;
color: #666;
margin-bottom: 8px;
}
.client-info .client-name {
font-size: 18px;
color: #1a1a2e;
font-weight: 600;
}
.permissions {
margin-bottom: 24px;
}
.permissions h3 {
font-size: 14px;
color: #666;
margin-bottom: 12px;
}
.permission-item {
display: flex;
align-items: center;
padding: 8px 0;
color: #333;
}
.permission-item svg {
width: 20px;
height: 20px;
margin-right: 12px;
fill: #28a745;
}
.form-group {
margin-bottom: 20px;
}
.form-group label {
display: block;
font-size: 14px;
color: #666;
margin-bottom: 8px;
}
.form-group input {
width: 100%;
padding: 12px 16px;
border: 2px solid #e1e5e9;
border-radius: 8px;
font-size: 16px;
transition: border-color 0.2s;
}
.form-group input:focus {
outline: none;
border-color: #0069ff;
}
.btn {
width: 100%;
padding: 14px;
border: none;
border-radius: 8px;
font-size: 16px;
font-weight: 600;
cursor: pointer;
transition: all 0.2s;
}
.btn-primary {
background: #0069ff;
color: white;
}
.btn-primary:hover {
background: #0056d6;
}
.btn-primary:disabled {
background: #ccc;
cursor: not-allowed;
}
.btn-cancel {
background: transparent;
color: #666;
margin-top: 12px;
}
.btn-cancel:hover {
color: #333;
}
.error {
background: #fff5f5;
border: 1px solid #fc8181;
color: #c53030;
padding: 12px;
border-radius: 8px;
margin-bottom: 16px;
font-size: 14px;
display: none;
}
.footer {
text-align: center;
margin-top: 24px;
font-size: 12px;
color: #999;
}
</style>
</head>
<body>
<div class="container">
<div class="logo">
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 17.93c-3.95-.49-7-3.85-7-7.93 0-.62.08-1.21.21-1.79L9 15v1c0 1.1.9 2 2 2v1.93zm6.9-2.54c-.26-.81-1-1.39-1.9-1.39h-1v-3c0-.55-.45-1-1-1H8v-2h2c.55 0 1-.45 1-1V7h2c1.1 0 2-.9 2-2v-.41c2.93 1.19 5 4.06 5 7.41 0 2.08-.8 3.97-2.1 5.39z"/>
</svg>
<h1>UniFi MCP Server</h1>
</div>
<div class="client-info">
<h2>Authorize Application</h2>
<div class="client-name">{{CLIENT_NAME}}</div>
</div>
<div class="permissions">
<h3>This application will be able to:</h3>
<div class="permission-item">
<svg viewBox="0 0 24 24"><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/></svg>
<span>View your UniFi network status</span>
</div>
<div class="permission-item">
<svg viewBox="0 0 24 24"><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/></svg>
<span>Manage devices and clients</span>
</div>
<div class="permission-item">
<svg viewBox="0 0 24 24"><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/></svg>
<span>Control cameras and access points</span>
</div>
</div>
<div class="error" id="error"></div>
<form id="authForm">
<input type="hidden" name="client_id" value="{{CLIENT_ID}}">
<input type="hidden" name="redirect_uri" value="{{REDIRECT_URI}}">
<input type="hidden" name="response_type" value="code">
<input type="hidden" name="state" value="{{STATE}}">
<input type="hidden" name="scope" value="{{SCOPE}}">
<input type="hidden" name="code_challenge" value="{{CODE_CHALLENGE}}">
<input type="hidden" name="code_challenge_method" value="{{CODE_CHALLENGE_METHOD}}">
<div class="form-group">
<label for="password">Authorization Password</label>
<input type="password" id="password" name="password" placeholder="Enter your password" required autocomplete="current-password">
</div>
<button type="submit" class="btn btn-primary" id="submitBtn">Authorize</button>
<button type="button" class="btn btn-cancel" onclick="history.back()">Cancel</button>
</form>
<div class="footer">
UniFi MCP Server • Secure OAuth 2.0
</div>
</div>
<script>
const form = document.getElementById('authForm');
const error = document.getElementById('error');
const submitBtn = document.getElementById('submitBtn');
form.addEventListener('submit', async (e) => {
e.preventDefault();
error.style.display = 'none';
submitBtn.disabled = true;
submitBtn.textContent = 'Authorizing...';
const formData = new FormData(form);
const data = Object.fromEntries(formData.entries());
try {
const response = await fetch('/oauth/authorize', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
});
const result = await response.json();
if (response.ok && result.redirect) {
window.location.href = result.redirect;
} else {
error.textContent = result.error_description || result.error || 'Authorization failed';
error.style.display = 'block';
submitBtn.disabled = false;
submitBtn.textContent = 'Authorize';
}
} catch (err) {
error.textContent = 'Network error. Please try again.';
error.style.display = 'block';
submitBtn.disabled = false;
submitBtn.textContent = 'Authorize';
}
});
</script>
</body>
</html>