fix(web): simplify first-time token sign-in
This commit is contained in:
@@ -26,7 +26,7 @@ export function AuthScreen({ authTokenInput, setAuthTokenInput, isSigningIn, aut
|
||||
</div>
|
||||
<div>
|
||||
<h1 className="text-lg font-semibold text-violet-50">Sign in to Sybil</h1>
|
||||
<p className="mt-1 text-sm text-muted-foreground">Use your backend admin token.</p>
|
||||
<p className="mt-1 text-sm text-muted-foreground">Enter your admin token.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -34,28 +34,27 @@ export function AuthScreen({ authTokenInput, setAuthTokenInput, isSigningIn, aut
|
||||
className="space-y-3"
|
||||
onSubmit={(event) => {
|
||||
event.preventDefault();
|
||||
void onSignIn(authTokenInput.trim() || null);
|
||||
const token = authTokenInput.trim();
|
||||
if (token) void onSignIn(token);
|
||||
}}
|
||||
>
|
||||
<Input
|
||||
type="password"
|
||||
autoComplete="off"
|
||||
aria-label="Admin token"
|
||||
placeholder="ADMIN_TOKEN"
|
||||
required
|
||||
value={authTokenInput}
|
||||
onInput={(event) => setAuthTokenInput(event.currentTarget.value)}
|
||||
disabled={isSigningIn}
|
||||
className="bg-[hsl(235_48%_6%_/_0.84)] text-violet-50"
|
||||
/>
|
||||
<Button className="w-full" type="submit" disabled={isSigningIn}>
|
||||
<Button className="w-full" type="submit" disabled={isSigningIn || !authTokenInput.trim()}>
|
||||
{isSigningIn ? "Signing in..." : "Sign in"}
|
||||
</Button>
|
||||
<Button className="w-full" type="button" variant="secondary" disabled={isSigningIn} onClick={() => void onSignIn(null)}>
|
||||
Continue without token
|
||||
</Button>
|
||||
</form>
|
||||
|
||||
{authError ? <p className="mt-3 text-sm text-red-600">{authError}</p> : null}
|
||||
<p className="mt-3 text-xs text-muted-foreground">If `ADMIN_TOKEN` is set in `/server/.env`, token login is required.</p>
|
||||
{authError ? <p role="alert" className="mt-3 text-sm text-red-600">{authError}</p> : null}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -18,8 +18,11 @@ function persistToken(token: string | null) {
|
||||
}
|
||||
|
||||
function normalizeAuthError(message: string) {
|
||||
if (message.includes("missing bearer token") || message.includes("invalid bearer token")) {
|
||||
return "Authentication failed. Enter the ADMIN_TOKEN configured in server/.env.";
|
||||
if (message.includes("invalid bearer token")) {
|
||||
return "Incorrect token. Please try again.";
|
||||
}
|
||||
if (message.includes("missing bearer token")) {
|
||||
return "Enter your admin token.";
|
||||
}
|
||||
return message;
|
||||
}
|
||||
@@ -43,10 +46,10 @@ export function useSessionAuth() {
|
||||
persistToken(tokenCandidate);
|
||||
};
|
||||
|
||||
const handleAuthFailure = (message: string) => {
|
||||
const handleAuthFailure = (message: string | null) => {
|
||||
setIsAuthenticated(false);
|
||||
setAuthMode(null);
|
||||
setAuthError(normalizeAuthError(message));
|
||||
setAuthError(message ? normalizeAuthError(message) : null);
|
||||
setAuthToken(null);
|
||||
persistToken(null);
|
||||
};
|
||||
@@ -81,7 +84,8 @@ export function useSessionAuth() {
|
||||
await completeSessionCheck(token);
|
||||
} catch (err) {
|
||||
const message = err instanceof Error ? err.message : String(err);
|
||||
handleAuthFailure(message);
|
||||
// A first visit without a token is an invitation to sign in, not a failed attempt.
|
||||
handleAuthFailure(!token && message.includes("missing bearer token") ? null : message);
|
||||
} finally {
|
||||
setIsCheckingSession(false);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user