Add auth code input flow for headless OAuth
This commit is contained in:
parent
68968fe7f4
commit
3ca9c8fb92
1 changed files with 46 additions and 5 deletions
|
|
@ -80,9 +80,12 @@ const App = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const [loginLoading, setLoginLoading] = useState(false);
|
const [loginLoading, setLoginLoading] = useState(false);
|
||||||
|
const [authCode, setAuthCode] = useState('');
|
||||||
|
const [codeSubmitting, setCodeSubmitting] = useState(false);
|
||||||
|
|
||||||
const handleLogin = async () => {
|
const handleLogin = async () => {
|
||||||
setLoginLoading(true);
|
setLoginLoading(true);
|
||||||
|
setAuthCode('');
|
||||||
try {
|
try {
|
||||||
const response = await fetch('/api/auth/login', { method: 'POST' });
|
const response = await fetch('/api/auth/login', { method: 'POST' });
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
|
|
@ -99,6 +102,29 @@ const App = () => {
|
||||||
setLoginLoading(false);
|
setLoginLoading(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleSubmitCode = async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
if (!authCode.trim()) return;
|
||||||
|
setCodeSubmitting(true);
|
||||||
|
try {
|
||||||
|
const response = await fetch('/api/auth/code', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ code: authCode.trim() })
|
||||||
|
});
|
||||||
|
const data = await response.json();
|
||||||
|
if (data.status === 'logged_in') {
|
||||||
|
setAuthCode('');
|
||||||
|
fetchAuthStatus();
|
||||||
|
} else {
|
||||||
|
alert(data.message || 'Code submission failed');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error submitting auth code:', error);
|
||||||
|
}
|
||||||
|
setCodeSubmitting(false);
|
||||||
|
};
|
||||||
|
|
||||||
const handleLogout = async () => {
|
const handleLogout = async () => {
|
||||||
try {
|
try {
|
||||||
await fetch('/api/auth/logout', { method: 'POST' });
|
await fetch('/api/auth/logout', { method: 'POST' });
|
||||||
|
|
@ -229,7 +255,13 @@ const App = () => {
|
||||||
{authStatus?.status === 'logged_in' ? (
|
{authStatus?.status === 'logged_in' ? (
|
||||||
<span className="auth-ok" title={authStatus.account}>● {authStatus.account || 'Logged in'}</span>
|
<span className="auth-ok" title={authStatus.account}>● {authStatus.account || 'Logged in'}</span>
|
||||||
) : authStatus?.status === 'pending' ? (
|
) : authStatus?.status === 'pending' ? (
|
||||||
<span className="auth-pending">⏳ Awaiting login…</span>
|
<form className="header-code-form" onSubmit={handleSubmitCode}>
|
||||||
|
<input type="text" placeholder="Paste auth code here" value={authCode}
|
||||||
|
onChange={e => setAuthCode(e.target.value)} className="header-code-input" />
|
||||||
|
<button type="submit" className="header-code-btn" disabled={codeSubmitting}>
|
||||||
|
{codeSubmitting ? '…' : '→'}
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
) : (
|
) : (
|
||||||
<button className="auth-login-btn" onClick={handleLogin} disabled={loginLoading}>
|
<button className="auth-login-btn" onClick={handleLogin} disabled={loginLoading}>
|
||||||
{loginLoading ? '⏳ Connecting…' : '🔐 Login with Claude Max'}
|
{loginLoading ? '⏳ Connecting…' : '🔐 Login with Claude Max'}
|
||||||
|
|
@ -301,14 +333,23 @@ const App = () => {
|
||||||
) : authStatus?.status === 'pending' ? (
|
) : authStatus?.status === 'pending' ? (
|
||||||
<div className="auth-pending-panel">
|
<div className="auth-pending-panel">
|
||||||
<span className="auth-icon">⏳</span>
|
<span className="auth-icon">⏳</span>
|
||||||
<div>
|
<div className="auth-pending-content">
|
||||||
<div className="auth-title">Waiting for browser login…</div>
|
<div className="auth-title">Waiting for authorization code…</div>
|
||||||
<div className="auth-sub">Complete the login in the browser tab that opened, then come back here.</div>
|
<div className="auth-sub">1. Click the link below to authorize in your browser</div>
|
||||||
|
<div className="auth-sub">2. After authorizing, you'll see a code — paste it below</div>
|
||||||
{authStatus.auth_url && (
|
{authStatus.auth_url && (
|
||||||
<a className="auth-url-link" href={authStatus.auth_url} target="_blank" rel="noreferrer">
|
<a className="auth-url-link" href={authStatus.auth_url} target="_blank" rel="noreferrer">
|
||||||
Click here if the browser tab didn't open →
|
Open authorization page →
|
||||||
</a>
|
</a>
|
||||||
)}
|
)}
|
||||||
|
<form className="auth-code-form" onSubmit={handleSubmitCode}>
|
||||||
|
<input type="text" placeholder="Paste your authorization code here"
|
||||||
|
value={authCode} onChange={e => setAuthCode(e.target.value)}
|
||||||
|
className="auth-code-input" />
|
||||||
|
<button type="submit" className="btn btn-primary btn-sm" disabled={codeSubmitting}>
|
||||||
|
{codeSubmitting ? 'Verifying…' : 'Submit Code'}
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
|
|
|
||||||
Reference in a new issue