mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-19 05:26:47 +00:00
feat(auth): explain the plain-HTTP secure-cookie gotcha on login
When the server issues a Secure session cookie but the request arrived over plain HTTP (the common LAN install over http://ip:3000), the browser drops the cookie and the next request dead-ends on a bare "Access token required" — the top source of avoidable install issues. The login response now flags this exact case and the login page shows a localized box explaining the fix (use HTTPS, or set COOKIE_SECURE=false) with a link to the Troubleshooting guide. It only triggers in the real failure case, never for correct HTTPS setups.
This commit is contained in:
@@ -11,7 +11,7 @@ export default function LoginPage(): React.ReactElement {
|
||||
navigate,
|
||||
mode, setMode,
|
||||
username, setUsername, email, setEmail, password, setPassword, rememberMe, setRememberMe, showPassword, setShowPassword,
|
||||
isLoading, error, setError, appConfig, inviteToken,
|
||||
isLoading, error, setError, insecureCookie, appConfig, inviteToken,
|
||||
langDropdownOpen, setLangDropdownOpen, setLanguageLocal,
|
||||
showTakeoff, mfaStep, setMfaStep, mfaToken, setMfaToken, mfaCode, setMfaCode,
|
||||
passwordChangeStep, newPassword, setNewPassword, confirmPassword, setConfirmPassword,
|
||||
@@ -447,6 +447,17 @@ export default function LoginPage(): React.ReactElement {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{insecureCookie && (
|
||||
<div style={{ padding: '12px 14px', background: '#fffbeb', border: '1px solid #fde68a', borderRadius: 10, fontSize: 'calc(13px * var(--fs-scale-body, 1))', color: '#92400e' }}>
|
||||
<div style={{ fontWeight: 700, marginBottom: 4 }}>{t('login.insecureCookie.title')}</div>
|
||||
<div style={{ lineHeight: 1.55 }}>{t('login.insecureCookie.body')}</div>
|
||||
<a href="https://github.com/mauriceboe/TREK/wiki/Troubleshooting" target="_blank" rel="noopener noreferrer"
|
||||
style={{ display: 'inline-block', marginTop: 6, fontWeight: 600, color: '#b45309', textDecoration: 'underline' }}>
|
||||
{t('login.insecureCookie.link')} ↗
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{passwordChangeStep && (
|
||||
<>
|
||||
<div style={{ padding: '10px 14px', background: '#fefce8', border: '1px solid #fde68a', borderRadius: 10, fontSize: 'calc(13px * var(--fs-scale-body, 1))', color: '#92400e' }}>
|
||||
|
||||
@@ -41,6 +41,9 @@ export function useLogin() {
|
||||
const [showPassword, setShowPassword] = useState<boolean>(false)
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false)
|
||||
const [error, setError] = useState<string>('')
|
||||
// Set when the server signals it just issued a Secure cookie over plain HTTP —
|
||||
// the browser drops it, so we explain the fix instead of a bare 401 later.
|
||||
const [insecureCookie, setInsecureCookie] = useState(false)
|
||||
const [appConfig, setAppConfig] = useState<AppConfig | null>(null)
|
||||
const [inviteToken, setInviteToken] = useState<string>('')
|
||||
const [inviteValid, setInviteValid] = useState<boolean>(false)
|
||||
@@ -225,6 +228,7 @@ export function useLogin() {
|
||||
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>): Promise<void> => {
|
||||
e.preventDefault()
|
||||
setError('')
|
||||
setInsecureCookie(false)
|
||||
setIsLoading(true)
|
||||
try {
|
||||
if (passwordChangeStep) {
|
||||
@@ -260,6 +264,13 @@ export function useLogin() {
|
||||
await register(username, email, password, inviteToken || undefined)
|
||||
} else {
|
||||
const result = await login(email, password, rememberMe)
|
||||
if ((result as { insecureCookie?: boolean }).insecureCookie) {
|
||||
// Credentials were correct, but the secure cookie won't survive plain
|
||||
// HTTP — proceeding would just dead-end on "Access token required".
|
||||
setInsecureCookie(true)
|
||||
setIsLoading(false)
|
||||
return
|
||||
}
|
||||
if ('mfa_required' in result && result.mfa_required && 'mfa_token' in result) {
|
||||
setMfaToken(result.mfa_token)
|
||||
setMfaStep(true)
|
||||
@@ -291,7 +302,7 @@ export function useLogin() {
|
||||
navigate,
|
||||
mode, setMode,
|
||||
username, setUsername, email, setEmail, password, setPassword, rememberMe, setRememberMe, showPassword, setShowPassword,
|
||||
isLoading, error, setError, appConfig, inviteToken,
|
||||
isLoading, error, setError, insecureCookie, appConfig, inviteToken,
|
||||
langDropdownOpen, setLangDropdownOpen, setLanguageLocal,
|
||||
showTakeoff, mfaStep, setMfaStep, mfaToken, setMfaToken, mfaCode, setMfaCode,
|
||||
passwordChangeStep, newPassword, setNewPassword, confirmPassword, setConfirmPassword,
|
||||
|
||||
Reference in New Issue
Block a user