Erstelle ein Auto-Login-System. Wenn jemand die URL /auto-login?token=TOKEN besucht, soll er automatisch eingeloggt werden, OHNE das Login-Formular zu sehen.
WICHTIG: Die Route /auto-login muss eine öffentliche Route sein — sie darf NICHT durch die Auth-Prüfung blockiert werden. Sie muss auch funktionieren, wenn der Nutzer nicht eingeloggt ist. Prüfe in App.jsx, ob es einen Auth-Guard gibt, der unangemeldete Nutzer auf die Login-Seite umleitet, und stelle sicher, dass /auto-login davon ausgenommen ist (genau wie die Login-Seite selbst).
Erstelle diese 3 Dateien und modifiziere 2 bestehende:
1. functions/validateFlowToken.js — Backend-Funktion die einen JWT verifiziert:
const SHARED_SECRET = Deno.env.get('DeutschFlow_Cooperativ_API_KEY');
async function verify(message, secret, signature) {
const enc = new TextEncoder();
const key = await crypto.subtle.importKey('raw', enc.encode(secret), { name: 'HMAC', hash: 'SHA-256' }, false, ['sign']);
const sig = await crypto.subtle.sign('HMAC', key, enc.encode(message));
const expected = btoa(String.fromCharCode(...new Uint8Array(sig))).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
return expected === signature;
}
Deno.serve(async (req) => {
try {
const { token } = await req.json();
const [header, payload, signature] = token.split('.');
const decoded = JSON.parse(atob(payload.replace(/-/g, '+').replace(/_/g, '/')));
if (Date.now() > decoded.exp) return Response.json({ valid: false }, { status: 401 });
const isValid = await verify(header + '.' + payload, SHARED_SECRET, signature);
if (!isValid) return Response.json({ valid: false }, { status: 401 });
return Response.json({ valid: true, email: decoded.email, name: decoded.name });
} catch (e) {
return Response.json({ valid: false, error: e.message }, { status: 500 });
}
});
2. lib/flowAuth.js:
export function getFlowUser() {
const match = document.cookie.match(/(?:^|;\s*)flow_user=([^;]+)/);
if (!match) return null;
try {
const email = decodeURIComponent(match[1]);
return { email, full_name: email.split("@")[0], role: "flow_member" };
} catch { return null; }
}
3. pages/AutoLogin.jsx:
import { useEffect } from "react";
import { useNavigate, useSearchParams } from "react-router-dom";
import { base44 } from "@/api/base44Client";
export default function AutoLogin() {
const [params] = useSearchParams();
const navigate = useNavigate();
useEffect(() => {
const token = params.get("token");
if (!token) { navigate("/"); return; }
base44.functions.invoke("validateFlowToken", { token })
.then(res => {
if (res.data?.valid) {
document.cookie = "flow_user=" + encodeURIComponent(res.data.email) + "; path=/; max-age=2592000; SameSite=Lax";
window.location.href = "/";
} else { navigate("/"); }
})
.catch(() => navigate("/"));
}, []);
return <div className="flex items-center justify-center min-h-screen text-lg">Anmeldung läuft…</div>;
}
4. lib/AuthContext.jsx — füge ganz am Anfang des useEffect (bevor base44.auth.me() aufgerufen wird) diesen Cookie-Check ein:
import { getFlowUser } from "@/lib/flowAuth";
// ... im useEffect:
const flowUser = getFlowUser();
if (flowUser) {
setUser(flowUser);
setIsLoadingAuth(false);
return;
}
// ... dann erst base44.auth.me()
5. App.jsx — füge /auto-login als öffentliche Route hinzu (gleiche Ebene wie Login, NICHT hinter dem Auth-Guard):
import AutoLogin from './pages/AutoLogin';
// ... in den öffentlichen Routes:
<Route path="/auto-login" element={<AutoLogin />} />