Skip to main content

Docusaurus Authentification Integration

Authentifizierung für geschützte Inhalten in Docusaurus mit Firebase und Typescript

Um Firebase-Authentifizierung in Ihre mit Docusaurus erstellte und auf GitHub Pages gehostete Website zu integrieren, können Sie die folgenden Schritte befolgen:

1. Firebase-Projekt einrichten:

• Erstellen Sie ein neues Projekt in der Firebase-Konsole.

• Navigieren Sie zu “Authentication” und aktivieren Sie die gewünschten Anmeldemethoden (z. B. E-Mail/Passwort, Google).

2. Firebase SDK hinzufügen:

• Installieren Sie das Firebase SDK in Ihrem Docusaurus-Projekt:

npm install firebase

• Erstellen Sie eine Konfigurationsdatei (z. B. firebaseConfig.ts) mit Ihren Firebase-Konfigurationsdetails:

// firebaseConfig.ts
import { initializeApp } from 'firebase/app';

const firebaseConfig = {
apiKey: 'YOUR_API_KEY',
authDomain: 'YOUR_AUTH_DOMAIN',
projectId: 'YOUR_PROJECT_ID',
storageBucket: 'YOUR_STORAGE_BUCKET',
messagingSenderId: 'YOUR_MESSAGING_SENDER_ID',
appId: 'YOUR_APP_ID',
};

const app = initializeApp(firebaseConfig);
export default app;

3. Root-Komponente anpassen:

Docusaurus ermöglicht das “Swizzling” von Komponenten, um sie anzupassen. Swizzlen Sie die Root-Komponente:

The Root component is rendered at the very top of the React tree, above the theme Layout, and never unmounts. It is the perfect place to add stateful logic that should not be re-initialized across navigations (user authentication status, shopping cart state...).

Swizzle it manually by creating a file at src/theme/Root.js:

• In der geswizzelten Root-Komponente (src/theme/Root.tsx), integrieren Sie die Firebase-Authentifizierung:

// src/theme/Root.tsx
import React, { useEffect, useState } from 'react';
import { onAuthStateChanged, getAuth } from 'firebase/auth';
import app from '../firebaseConfig';

const auth = getAuth(app);

export default function Root({ children }) {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);

useEffect(() => {
const unsubscribe = onAuthStateChanged(auth, (user) => {
setUser(user);
setLoading(false);
});
return () => unsubscribe();
}, []);

if (loading) {
return <div>Loading...</div>;
}

if (!user) {
return <div>Please log in to access this content.</div>;
}

return <>{children}</>;
}

• Stellen Sie sicher, dass Sie die entsprechenden Firebase-Authentifizierungsfunktionen (z. B. signInWithPopup, GoogleAuthProvider) implementieren, um die Anmeldung zu ermöglichen.

4. Zugriff auf bestimmte Bereiche einschränken:

• Um den Zugriff auf bestimmte Unterverzeichnisse oder Dateien einzuschränken, können Sie innerhalb der Root-Komponente die aktuelle Route überprüfen und basierend darauf die Authentifizierung erzwingen:

import { useLocation } from '@docusaurus/router';

export default function Root({ children }) {
// ... vorheriger Code ...

const location = useLocation();
const premiumPaths = ['/premium', '/docs/premium-guide'];

if (premiumPaths.includes(location.pathname) && !user) {
return <div>Please log in to access this content.</div>;
}

return <>{children}</>;
}

• Passen Sie die premiumPaths-Liste entsprechend den Pfaden an, die Sie schützen möchten.

5. Bereitstellung auf GitHub Pages:

• Stellen Sie sicher, dass Ihre Docusaurus-Site korrekt für die Bereitstellung auf GitHub Pages konfiguriert ist. Detaillierte Anweisungen finden Sie in der Docusaurus-Dokumentation.

Bitte beachten Sie, dass die Implementierung der Authentifizierung in einer statischen Site wie Docusaurus einige Einschränkungen mit sich bringt. Es ist wichtig, den Schutz sensibler Inhalte zu gewährleisten und sicherzustellen, dass keine vertraulichen Daten im öffentlichen Build Ihrer Site enthalten sind.

Weitere detaillierte Anleitungen und Beispiele finden Sie in diesem GitHub-Repository und in diesem Blogbeitrag.

Login- und Logout-Button

Hier ist eine vollständige Implementierung für die Integration eines Login- und Logout-Buttons in die Docusaurus-Navbar sowie Login- und Signup-Seiten mit ansprechendem Styling.

1. Login/Logout in Navbar einfügen

Docusaurus erlaubt das Anpassen der Navbar über das theme/Navbar.tsx-Swizzling.

Schritte:

2. Swizzle die Navbar:

npx docusaurus swizzle @docusaurus/theme-classic Navbar --typescript

3. Bearbeite src/theme/Navbar.tsx:

// src/theme/Navbar.tsx
import React, { useEffect, useState } from 'react';
import Navbar from '@theme-original/Navbar';
import { useHistory } from '@docusaurus/router';
import { getAuth, onAuthStateChanged, signOut } from 'firebase/auth';
import app from '../firebaseConfig';

const auth = getAuth(app);

export default function NavbarWrapper(props) {
const [user, setUser] = useState(null);
const history = useHistory();

useEffect(() => {
return onAuthStateChanged(auth, (user) => {
setUser(user);
});
}, []);

const handleLogout = async () => {
await signOut(auth);
history.push('/login');
};

return (
<Navbar {...props}>
<div style={{ marginLeft: 'auto', marginRight: '20px' }}>
{user ? (
<button onClick={handleLogout} className="nav-auth-button">Logout</button>
) : (
<button onClick={() => history.push('/login')} className="nav-auth-button">Login</button>
)}
</div>
</Navbar>
);
}

5. Füge Styles für den Button hinzu (src/css/custom.css):

.nav-auth-button {
background-color: #007bff;
color: white;
padding: 8px 12px;
border-radius: 5px;
border: none;
cursor: pointer;
font-size: 14px;
}

.nav-auth-button:hover {
background-color: #0056b3;
}

6. Login- und Signup-Seiten

Erstelle src/pages/login.tsx und src/pages/signup.tsx für die Authentifizierung.

Login-Seite (src/pages/login.tsx)

import React, { useState } from 'react';
import { getAuth, signInWithEmailAndPassword } from 'firebase/auth';
import { useHistory } from '@docusaurus/router';
import '../css/auth.css';

const Login = () => {
const auth = getAuth();
const history = useHistory();
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [error, setError] = useState('');

const handleLogin = async (e: React.FormEvent) => {
e.preventDefault();
try {
await signInWithEmailAndPassword(auth, email, password);
history.push('/');
} catch (err) {
setError('Invalid credentials. Please try again.');
}
};

return (
<div className="auth-container">
<h2>Login</h2>
{error && <p className="auth-error">{error}</p>}
<form onSubmit={handleLogin} className="auth-form">
<input type="email" placeholder="Email" value={email} onChange={(e) => setEmail(e.target.value)} required />
<input type="password" placeholder="Password" value={password} onChange={(e) => setPassword(e.target.value)} required />
<button type="submit">Login</button>
</form>
<p>Don't have an account? <a href="/signup">Sign up</a></p>
</div>
);
};

export default Login;

Signup-Seite (src/pages/signup.tsx)

import React, { useState } from 'react';
import { getAuth, createUserWithEmailAndPassword } from 'firebase/auth';
import { useHistory } from '@docusaurus/router';
import '../css/auth.css';

const Signup = () => {
const auth = getAuth();
const history = useHistory();
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [error, setError] = useState('');

const handleSignup = async (e: React.FormEvent) => {
e.preventDefault();
try {
await createUserWithEmailAndPassword(auth, email, password);
history.push('/');
} catch (err) {
setError('Error signing up. Try again.');
}
};

return (
<div className="auth-container">
<h2>Sign Up</h2>
{error && <p className="auth-error">{error}</p>}
<form onSubmit={handleSignup} className="auth-form">
<input type="email" placeholder="Email" value={email} onChange={(e) => setEmail(e.target.value)} required />
<input type="password" placeholder="Password" value={password} onChange={(e) => setPassword(e.target.value)} required />
<button type="submit">Sign Up</button>
</form>
<p>Already have an account? <a href="/login">Login</a></p>
</div>
);
};

export default Signup;

7. Styling für Auth-Seiten (src/css/auth.css)

.auth-container {
max-width: 400px;
margin: 100px auto;
padding: 20px;
text-align: center;
background: white;
border-radius: 8px;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
}

.auth-form {
display: flex;
flex-direction: column;
gap: 10px;
}

.auth-form input {
padding: 10px;
border: 1px solid #ccc;
border-radius: 5px;
font-size: 16px;
}

.auth-form button {
background-color: #007bff;
color: white;
padding: 10px;
border: none;
border-radius: 5px;
cursor: pointer;
font-size: 16px;
}

.auth-form button:hover {
background-color: #0056b3;
}

.auth-error {
color: red;
font-size: 14px;
}

8. Weiterleitung bei Authentifizierung

Falls du den Zugriff auf /premium oder andere geschützte Bereiche nur für eingeloggte Nutzer erlauben willst, kannst du in der Root-Komponente (src/theme/Root.tsx) den Zugriff überprüfen:

import { useLocation, useHistory } from '@docusaurus/router';

export default function Root({ children }) {
const location = useLocation();
const history = useHistory();
const premiumPaths = ['/premium', '/docs/premium-guide'];

useEffect(() => {
if (premiumPaths.includes(location.pathname) && !user) {
history.push('/login');
}
}, [location.pathname, user]);

return <>{children}</>;
}

Fazit

• Du hast jetzt eine Login- und Signup-Seite mit Firebase-Authentifizierung.

• Der Login- und Logout-Button wird in der Navbar rechts oben angezeigt.

• Geschützte Bereiche (/premium) sind nur für eingeloggte Benutzer zugänglich.

• Die Styling-Dateien sorgen für eine moderne und benutzerfreundliche UI.

Das Setup ist ideal für Docusaurus auf GitHub Pages mit Firebase Auth!

OAuth Logins

Um OAuth-Login mit Microsoft, Google, Apple, Facebook und GitHub in deine Docusaurus-Seite mit Firebase Auth zu integrieren, befolge diese Schritte:

  1. Firebase OAuth-Provider aktivieren
  2. Gehe in die Firebase Console.
  3. Wähle dein Projekt aus und navigiere zu Authentication → Sign-in Method.
  4. Aktiviere die gewünschten Anbieter (Google, Microsoft, Apple, Facebook, GitHub).
  5. Konfiguriere Client-ID & Secret für jeden Anbieter:

• Google: Direkt in Firebase einstellbar.

• Apple, Microsoft, Facebook, GitHub: Gehe zur jeweiligen Entwicklerplattform und registriere eine OAuth App.

• Trage die Client-ID und das Secret in Firebase ein.

• Setze die Redirect-URI auf:

https://your-firebase-app.firebaseapp.com/__/auth/handler

1. Firebase SDK für OAuth in firebaseConfig.ts anpassen

Falls noch nicht geschehen, installiere Firebase:

npm install firebase

Bearbeite firebaseConfig.ts:

import { initializeApp } from 'firebase/app';
import { getAuth } from 'firebase/auth';

const firebaseConfig = {
apiKey: 'YOUR_API_KEY',
authDomain: 'YOUR_AUTH_DOMAIN',
projectId: 'YOUR_PROJECT_ID',
storageBucket: 'YOUR_STORAGE_BUCKET',
messagingSenderId: 'YOUR_MESSAGING_SENDER_ID',
appId: 'YOUR_APP_ID',
};

const app = initializeApp(firebaseConfig);
export const auth = getAuth(app);
export default app;

2. Login mit OAuth in login.tsx implementieren

Ersetze den Code in src/pages/login.tsx:

import React from 'react';
import { getAuth, signInWithPopup, GoogleAuthProvider, GithubAuthProvider, OAuthProvider, FacebookAuthProvider } from 'firebase/auth';
import { useHistory } from '@docusaurus/router';
import '../css/auth.css';

const Login = () => {
const auth = getAuth();
const history = useHistory();

const handleOAuthLogin = async (provider: any) => {
try {
await signInWithPopup(auth, provider);
history.push('/');
} catch (error) {
console.error('Login error:', error);
}
};

return (
<div className="auth-container">
<h2>Login</h2>
<div className="auth-buttons">
<button className="google" onClick={() => handleOAuthLogin(new GoogleAuthProvider())}>Login mit Google</button>
<button className="microsoft" onClick={() => handleOAuthLogin(new OAuthProvider('microsoft.com'))}>Login mit Microsoft</button>
<button className="apple" onClick={() => handleOAuthLogin(new OAuthProvider('apple.com'))}>Login mit Apple</button>
<button className="facebook" onClick={() => handleOAuthLogin(new FacebookAuthProvider())}>Login mit Facebook</button>
<button className="github" onClick={() => handleOAuthLogin(new GithubAuthProvider())}>Login mit GitHub</button>
</div>
<p>Oder <a href="/signup">registriere dich hier</a></p>
</div>
);
};

export default Login;

3. Registrierung (signup.tsx) mit OAuth

Ersetze den Code in src/pages/signup.tsx:

import React from 'react';
import { getAuth, signInWithPopup, GoogleAuthProvider, GithubAuthProvider, OAuthProvider, FacebookAuthProvider } from 'firebase/auth';
import { useHistory } from '@docusaurus/router';
import '../css/auth.css';

const Signup = () => {
const auth = getAuth();
const history = useHistory();

const handleOAuthSignup = async (provider: any) => {
try {
await signInWithPopup(auth, provider);
history.push('/');
} catch (error) {
console.error('Signup error:', error);
}
};

return (
<div className="auth-container">
<h2>Registrieren</h2>
<div className="auth-buttons">
<button className="google" onClick={() => handleOAuthSignup(new GoogleAuthProvider())}>Mit Google registrieren</button>
<button className="microsoft" onClick={() => handleOAuthSignup(new OAuthProvider('microsoft.com'))}>Mit Microsoft registrieren</button>
<button className="apple" onClick={() => handleOAuthSignup(new OAuthProvider('apple.com'))}>Mit Apple registrieren</button>
<button className="facebook" onClick={() => handleOAuthSignup(new FacebookAuthProvider())}>Mit Facebook registrieren</button>
<button className="github" onClick={() => handleOAuthSignup(new GithubAuthProvider())}>Mit GitHub registrieren</button>
</div>
<p>Bereits ein Konto? <a href="/login">Hier einloggen</a></p>
</div>
);
};

export default Signup;

4. Styles für die Auth-Buttons (src/css/auth.css)

.auth-container {
max-width: 400px;
margin: 100px auto;
padding: 20px;
text-align: center;
background: white;
border-radius: 8px;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
}

.auth-buttons {
display: flex;
flex-direction: column;
gap: 10px;
}

.auth-buttons button {
padding: 10px;
font-size: 16px;
border: none;
border-radius: 5px;
cursor: pointer;
color: white;
}

.google {
background-color: #db4437;
}

.microsoft {
background-color: #0078d4;
}

.apple {
background-color: #333;
}

.facebook {
background-color: #3b5998;
}

.github {
background-color: #24292e;
}

.auth-buttons button:hover {
opacity: 0.8;
}

5. Navbar aktualisieren (src/theme/Navbar.tsx)

Falls noch nicht getan, passe die Navbar.tsx an, um den OAuth-Login sichtbar zu machen:

import React, { useEffect, useState } from 'react';
import Navbar from '@theme-original/Navbar';
import { useHistory } from '@docusaurus/router';
import { getAuth, onAuthStateChanged, signOut } from 'firebase/auth';
import app from '../firebaseConfig';

const auth = getAuth(app);

export default function NavbarWrapper(props) {
const [user, setUser] = useState(null);
const history = useHistory();

useEffect(() => {
return onAuthStateChanged(auth, (user) => {
setUser(user);
});
}, []);

const handleLogout = async () => {
await signOut(auth);
history.push('/login');
};

return (
<Navbar {...props}>
<div style={{ marginLeft: 'auto', marginRight: '20px' }}>
{user ? (
<>
<span>Willkommen, {user.displayName}</span>
<button onClick={handleLogout} className="nav-auth-button">Logout</button>
</>
) : (
<button onClick={() => history.push('/login')} className="nav-auth-button">Login</button>
)}
</div>
</Navbar>
);
}

Fazit

✅ OAuth-Login mit Microsoft, Google, Apple, Facebook, GitHub in Docusaurus integriert.

✅ Login & Signup-Seiten mit ansprechendem Styling.

✅ OAuth-Buttons für nahtlosen Zugriff.

✅ Navbar mit Login-Status aktualisiert.

Jetzt kannst du Firebase Auth nutzen, um Benutzer über OAuth zu authentifizieren!

Um die Anmeldung mit Login-Code per E-Mail oder SMS sowie die E-Mail-Bestätigung für E-Mail/Passwort-Registrierung in dein Docusaurus-Projekt mit Firebase Auth zu integrieren, folgen hier die notwendigen Schritte.

  1. Firebase-Einstellungen
  2. Gehe in die Firebase Console.
  3. Authentication → Sign-in Method:

• E-Mail/Passwort aktivieren.

• E-Mail-Link (ohne Passwort) aktivieren (für Login per E-Mail-Code).

• Telefon (SMS) aktivieren (für Login per SMS-Code).

1. Authentication → Templates:

• Passe die E-Mail-Bestätigungsmail an.

Der Nutzer gibt seine E-Mail ein und erhält einen Login-Link. Nach dem Klick darauf wird er angemeldet.

emailLogin.tsx

import React, { useState } from 'react';
import { getAuth, sendSignInLinkToEmail, isSignInWithEmailLink, signInWithEmailLink } from 'firebase/auth';
import { useHistory } from '@docusaurus/router';
import '../css/auth.css';

const EmailLogin = () => {
const auth = getAuth();
const history = useHistory();
const [email, setEmail] = useState('');
const [message, setMessage] = useState('');

const handleSendLink = async (e: React.FormEvent) => {
e.preventDefault();
try {
const actionCodeSettings = {
url: window.location.origin + '/emailLogin',
handleCodeInApp: true,
};
await sendSignInLinkToEmail(auth, email, actionCodeSettings);
localStorage.setItem('emailForSignIn', email);
setMessage('Überprüfe deine E-Mails für den Login-Link.');
} catch (error) {
console.error(error);
setMessage('Fehler beim Senden des Links.');
}
};

React.useEffect(() => {
if (isSignInWithEmailLink(auth, window.location.href)) {
let email = localStorage.getItem('emailForSignIn');
if (!email) {
email = prompt('Bitte bestätige deine E-Mail-Adresse:');
}
if (email) {
signInWithEmailLink(auth, email, window.location.href)
.then(() => {
localStorage.removeItem('emailForSignIn');
history.push('/');
})
.catch((error) => console.error(error));
}
}
}, [auth, history]);

return (
<div className="auth-container">
<h2>Login per E-Mail-Link</h2>
{message && <p className="auth-message">{message}</p>}
<form onSubmit={handleSendLink} className="auth-form">
<input type="email" placeholder="E-Mail" value={email} onChange={(e) => setEmail(e.target.value)} required />
<button type="submit">Login-Link senden</button>
</form>
</div>
);
};

export default EmailLogin;

3. Anmeldung per SMS-Code

Der Nutzer gibt seine Telefonnummer ein, erhält einen Code per SMS und meldet sich mit diesem Code an.

phoneLogin.tsx

import React, { useState } from 'react';
import { getAuth, RecaptchaVerifier, signInWithPhoneNumber } from 'firebase/auth';
import { useHistory } from '@docusaurus/router';
import '../css/auth.css';

const PhoneLogin = () => {
const auth = getAuth();
const history = useHistory();
const [phone, setPhone] = useState('');
const [code, setCode] = useState('');
const [confirmationResult, setConfirmationResult] = useState<any>(null);

const handleSendCode = async (e: React.FormEvent) => {
e.preventDefault();
try {
window.recaptchaVerifier = new RecaptchaVerifier(auth, 'recaptcha-container', { size: 'invisible' });
const result = await signInWithPhoneNumber(auth, phone, window.recaptchaVerifier);
setConfirmationResult(result);
} catch (error) {
console.error(error);
}
};

const handleVerifyCode = async (e: React.FormEvent) => {
e.preventDefault();
try {
await confirmationResult.confirm(code);
history.push('/');
} catch (error) {
console.error(error);
}
};

return (
<div className="auth-container">
<h2>Login per SMS</h2>
<div id="recaptcha-container"></div>
{!confirmationResult ? (
<form onSubmit={handleSendCode} className="auth-form">
<input type="tel" placeholder="Telefonnummer" value={phone} onChange={(e) => setPhone(e.target.value)} required />
<button type="submit">Code senden</button>
</form>
) : (
<form onSubmit={handleVerifyCode} className="auth-form">
<input type="text" placeholder="SMS-Code" value={code} onChange={(e) => setCode(e.target.value)} required />
<button type="submit">Code bestätigen</button>
</form>
)}
</div>
);
};

export default PhoneLogin;

4. Bestätigungsmail für E-Mail/Passwort-Registrierung

Nach der Registrierung erhält der Nutzer eine Bestätigungs-E-Mail. Erst nach Bestätigung kann er sich einloggen.

signup.tsx mit E-Mail-Verifikation

import React, { useState } from 'react';
import { getAuth, createUserWithEmailAndPassword, sendEmailVerification } from 'firebase/auth';
import { useHistory } from '@docusaurus/router';
import '../css/auth.css';

const Signup = () => {
const auth = getAuth();
const history = useHistory();
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [message, setMessage] = useState('');

const handleSignup = async (e: React.FormEvent) => {
e.preventDefault();
try {
const userCredential = await createUserWithEmailAndPassword(auth, email, password);
await sendEmailVerification(userCredential.user);
setMessage('Bestätigungs-E-Mail gesendet. Bitte überprüfe deine E-Mails.');
} catch (error) {
console.error(error);
setMessage('Fehler bei der Registrierung.');
}
};

return (
<div className="auth-container">
<h2>Registrieren</h2>
{message && <p className="auth-message">{message}</p>}
<form onSubmit={handleSignup} className="auth-form">
<input type="email" placeholder="E-Mail" value={email} onChange={(e) => setEmail(e.target.value)} required />
<input type="password" placeholder="Passwort" value={password} onChange={(e) => setPassword(e.target.value)} required />
<button type="submit">Registrieren</button>
</form>
</div>
);
};

export default Signup;

5. Login sperren, falls E-Mail nicht verifiziert

Ändere den Login-Prozess, um nicht verifizierte Nutzer zu blockieren.

login.tsx mit Verifizierungs-Check

const handleLogin = async (e: React.FormEvent) => {
e.preventDefault();
try {
const userCredential = await signInWithEmailAndPassword(auth, email, password);
if (!userCredential.user.emailVerified) {
setMessage('Bitte bestätige zuerst deine E-Mail-Adresse.');
await sendEmailVerification(userCredential.user);
return;
}
history.push('/');
} catch (err) {
setMessage('Login fehlgeschlagen.');
}
};

Fazit

✅ Login per Magic Link (E-Mail)

✅ Login per SMS-Code

✅ E-Mail-Verifizierung nach Registrierung

✅ Login nur nach Bestätigung erlaubt

Jetzt sind alle modernen Anmeldeoptionen mit Firebase Auth in Docusaurus verfügbar!

GitHub Style und Popup Modals

Hier ist eine überarbeitete Version des Login- und Signup-Systems, die sich stilistisch an GitHub anlehnt und die Authentifizierungsformulare als Popup (Modal) öffnet.

1. Styles an GitHub anpassen

Erstelle oder bearbeite src/css/auth.css:

/* Auth Modal */
.auth-modal {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: #f6f8fa;
padding: 20px;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
width: 400px;
max-width: 90%;
}

.auth-modal h2 {
font-size: 20px;
color: #24292f;
text-align: center;
margin-bottom: 16px;
}

.auth-form {
display: flex;
flex-direction: column;
gap: 12px;
}

.auth-form input {
padding: 10px;
border: 1px solid #d1d5da;
border-radius: 6px;
font-size: 16px;
background: white;
color: #24292f;
}

.auth-form button {
background-color: #2ea44f;
color: white;
font-size: 16px;
padding: 10px;
border-radius: 6px;
cursor: pointer;
font-weight: bold;
}

.auth-form button:hover {
background-color: #22863a;
}

.auth-options {
display: flex;
flex-direction: column;
gap: 10px;
text-align: center;
}

.auth-options button {
background-color: #fafbfc;
color: #24292f;
font-size: 16px;
padding: 10px;
border: 1px solid #d1d5da;
border-radius: 6px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
}

.auth-options button:hover {
background-color: #f3f4f6;
}

.auth-options img {
height: 20px;
margin-right: 10px;
}

.auth-message {
color: red;
font-size: 14px;
text-align: center;
}

/* Overlay for modal */
.auth-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.3);
display: flex;
justify-content: center;
align-items: center;
}

/* Close button */
.auth-close {
position: absolute;
right: 10px;
top: 10px;
font-size: 18px;
cursor: pointer;
}

2. Login & Signup als Popup-Modale

Erstelle src/components/AuthModal.tsx für die modalen Login- und Signup-Formulare.

AuthModal.tsx

import React, { useState } from 'react';
import { getAuth, signInWithPopup, GoogleAuthProvider, GithubAuthProvider, signInWithEmailAndPassword, createUserWithEmailAndPassword, sendEmailVerification } from 'firebase/auth';
import '../css/auth.css';

interface AuthModalProps {
isOpen: boolean;
onClose: () => void;
}

const AuthModal: React.FC<AuthModalProps> = ({ isOpen, onClose }) => {
const auth = getAuth();
const [isLogin, setIsLogin] = useState(true);
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [message, setMessage] = useState('');

if (!isOpen) return null;

const handleOAuthLogin = async (provider: any) => {
try {
await signInWithPopup(auth, provider);
onClose();
} catch (error) {
console.error(error);
setMessage('Fehler bei der Anmeldung.');
}
};

const handleAuth = async (e: React.FormEvent) => {
e.preventDefault();
try {
if (isLogin) {
const userCredential = await signInWithEmailAndPassword(auth, email, password);
if (!userCredential.user.emailVerified) {
setMessage('Bitte bestätige deine E-Mail-Adresse.');
await sendEmailVerification(userCredential.user);
return;
}
} else {
const userCredential = await createUserWithEmailAndPassword(auth, email, password);
await sendEmailVerification(userCredential.user);
setMessage('Bestätigungs-E-Mail gesendet.');
}
onClose();
} catch (error) {
console.error(error);
setMessage('Fehler bei der Registrierung.');
}
};

return (
<div className="auth-overlay">
<div className="auth-modal">
<span className="auth-close" onClick={onClose}>&times;</span>
<h2>{isLogin ? 'Anmelden' : 'Registrieren'}</h2>
{message && <p className="auth-message">{message}</p>}

<form onSubmit={handleAuth} className="auth-form">
<input type="email" placeholder="E-Mail" value={email} onChange={(e) => setEmail(e.target.value)} required />
<input type="password" placeholder="Passwort" value={password} onChange={(e) => setPassword(e.target.value)} required />
<button type="submit">{isLogin ? 'Anmelden' : 'Registrieren'}</button>
</form>

<div className="auth-options">
<button onClick={() => handleOAuthLogin(new GoogleAuthProvider())}>
<img src="https://upload.wikimedia.org/wikipedia/commons/5/53/Google_%22G%22_Logo.svg" alt="Google" />
Mit Google anmelden
</button>
<button onClick={() => handleOAuthLogin(new GithubAuthProvider())}>
<img src="https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png" alt="GitHub" />
Mit GitHub anmelden
</button>
</div>

<p style={{ textAlign: 'center', cursor: 'pointer', marginTop: '10px' }} onClick={() => setIsLogin(!isLogin)}>
{isLogin ? 'Noch kein Konto? Registrieren' : 'Bereits registriert? Anmelden'}
</p>
</div>
</div>
);
};

export default AuthModal;

3. Navbar-Button zum Öffnen des Popups

Bearbeite src/theme/Navbar.tsx, um den Button für den Login in die Navbar einzufügen.

Navbar.tsx

import React, { useEffect, useState } from 'react';
import Navbar from '@theme-original/Navbar';
import { getAuth, onAuthStateChanged, signOut } from 'firebase/auth';
import AuthModal from '../components/AuthModal';

const auth = getAuth();

export default function NavbarWrapper(props) {
const [user, setUser] = useState(null);
const [isAuthModalOpen, setAuthModalOpen] = useState(false);

useEffect(() => {
return onAuthStateChanged(auth, (user) => {
setUser(user);
});
}, []);

const handleLogout = async () => {
await signOut(auth);
};

return (
<>
<Navbar {...props}>
<div style={{ marginLeft: 'auto', marginRight: '20px' }}>
{user ? (
<>
<span style={{ marginRight: '10px' }}>Hallo, {user.displayName || 'User'}</span>
<button onClick={handleLogout} className="nav-auth-button">Logout</button>
</>
) : (
<button onClick={() => setAuthModalOpen(true)} className="nav-auth-button">Login</button>
)}
</div>
</Navbar>
<AuthModal isOpen={isAuthModalOpen} onClose={() => setAuthModalOpen(false)} />
</>
);
}

Fazit

✅ Styling an GitHub angepasst

✅ Login & Signup als Popup-Modale integriert

✅ OAuth mit Google & GitHub funktioniert

✅ Navbar-Button öffnet das Modal

Jetzt hat deine Docusaurus-Seite eine elegante, GitHub-ähnliche Authentifizierung! 🚀

Nutzer Profileinstellungen

Hier ist eine erweiterte Einstellungsseite für Nutzer, mit der sie ihr Passwort ändern, ihren Vor- und Nachnamen, Nutzernamen anpassen und Newsletter-Kategorien abonnieren können.

1. Firebase Firestore für Benutzerprofile aktivieren

Da Firebase Authentication keine erweiterten Benutzerfelder speichert (z. B. Name, Benutzername, Newsletter-Optionen), nutzen wir Firestore.

Firestore aktivieren:

  1. Gehe zur Firebase Console.
  2. Wähle dein Projekt aus und navigiere zu Firestore-Datenbank.
  3. Klicke auf Datenbank erstellen und wähle Modus starten.
  4. Erstelle eine Sammlung “users”.
  5. firebaseConfig.ts um Firestore erweitern

Falls noch nicht geschehen, installiere Firestore:

npm install firebase

Bearbeite firebaseConfig.ts:

import { initializeApp } from 'firebase/app';
import { getAuth } from 'firebase/auth';
import { getFirestore } from 'firebase/firestore';

const firebaseConfig = {
apiKey: 'YOUR_API_KEY',
authDomain: 'YOUR_AUTH_DOMAIN',
projectId: 'YOUR_PROJECT_ID',
storageBucket: 'YOUR_STORAGE_BUCKET',
messagingSenderId: 'YOUR_MESSAGING_SENDER_ID',
appId: 'YOUR_APP_ID',
};

const app = initializeApp(firebaseConfig);
export const auth = getAuth(app);
export const db = getFirestore(app);
export default app;

2. Settings.tsx für Benutzer-Einstellungen

Erstelle src/pages/settings.tsx mit folgendem Code:

import React, { useEffect, useState } from 'react';
import { getAuth, updatePassword, updateProfile } from 'firebase/auth';
import { doc, getDoc, setDoc } from 'firebase/firestore';
import { db } from '../firebaseConfig';
import '../css/auth.css';

const Settings = () => {
const auth = getAuth();
const user = auth.currentUser;
const [firstName, setFirstName] = useState('');
const [lastName, setLastName] = useState('');
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const [newsletter, setNewsletter] = useState<string[]>([]);
const [message, setMessage] = useState('');

useEffect(() => {
if (user) {
const fetchUserData = async () => {
const userDoc = await getDoc(doc(db, 'users', user.uid));
if (userDoc.exists()) {
const data = userDoc.data();
setFirstName(data.firstName || '');
setLastName(data.lastName || '');
setUsername(data.username || '');
setNewsletter(data.newsletter || []);
}
};
fetchUserData();
}
}, [user]);

const handleSaveProfile = async () => {
if (user) {
try {
await updateProfile(user, { displayName: `${firstName} ${lastName}` });
await setDoc(doc(db, 'users', user.uid), { firstName, lastName, username, newsletter }, { merge: true });
setMessage('Profil erfolgreich aktualisiert.');
} catch (error) {
setMessage('Fehler beim Speichern.');
}
}
};

const handlePasswordChange = async () => {
if (user && password) {
try {
await updatePassword(user, password);
setMessage('Passwort erfolgreich geändert.');
} catch (error) {
setMessage('Fehler beim Ändern des Passworts.');
}
}
};

const toggleNewsletter = (category: string) => {
setNewsletter((prev) =>
prev.includes(category) ? prev.filter((item) => item !== category) : [...prev, category]
);
};

return (
<div className="auth-container">
<h2>Einstellungen</h2>
{message && <p className="auth-message">{message}</p>}

<div className="auth-form">
<label>Vorname:</label>
<input type="text" value={firstName} onChange={(e) => setFirstName(e.target.value)} />

<label>Nachname:</label>
<input type="text" value={lastName} onChange={(e) => setLastName(e.target.value)} />

<label>Nutzername:</label>
<input type="text" value={username} onChange={(e) => setUsername(e.target.value)} />

<label>Neues Passwort:</label>
<input type="password" value={password} onChange={(e) => setPassword(e.target.value)} />

<h3>Newsletter-Kategorien:</h3>
<label>
<input type="checkbox" checked={newsletter.includes('tech')} onChange={() => toggleNewsletter('tech')} />
Technologie
</label>
<label>
<input type="checkbox" checked={newsletter.includes('finance')} onChange={() => toggleNewsletter('finance')} />
Finanzen
</label>
<label>
<input type="checkbox" checked={newsletter.includes('health')} onChange={() => toggleNewsletter('health')} />
Gesundheit
</label>

<button onClick={handleSaveProfile}>Profil speichern</button>
<button onClick={handlePasswordChange}>Passwort ändern</button>
</div>
</div>
);
};

export default Settings;

3. Styles für die Einstellungsseite (src/css/auth.css)

.auth-container {
max-width: 500px;
margin: 80px auto;
padding: 20px;
text-align: center;
background: #f6f8fa;
border-radius: 8px;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
}

.auth-form {
display: flex;
flex-direction: column;
gap: 10px;
}

.auth-form label {
font-weight: bold;
text-align: left;
display: block;
}

.auth-form input {
padding: 8px;
border: 1px solid #d1d5da;
border-radius: 5px;
font-size: 16px;
background: white;
}

.auth-form button {
background-color: #2ea44f;
color: white;
font-size: 16px;
padding: 10px;
border-radius: 6px;
cursor: pointer;
font-weight: bold;
margin-top: 10px;
}

.auth-form button:hover {
background-color: #22863a;
}

.auth-message {
color: red;
font-size: 14px;
}

Bearbeite src/theme/Navbar.tsx, um den Link zur Einstellungsseite hinzuzufügen:

import React, { useEffect, useState } from 'react';
import Navbar from '@theme-original/Navbar';
import { getAuth, onAuthStateChanged, signOut } from 'firebase/auth';
import { useHistory } from '@docusaurus/router';

const auth = getAuth();

export default function NavbarWrapper(props) {
const [user, setUser] = useState(null);
const history = useHistory();

useEffect(() => {
return onAuthStateChanged(auth, (user) => {
setUser(user);
});
}, []);

const handleLogout = async () => {
await signOut(auth);
history.push('/');
};

return (
<Navbar {...props}>
<div style={{ marginLeft: 'auto', marginRight: '20px' }}>
{user ? (
<>
<span onClick={() => history.push('/settings')} style={{ cursor: 'pointer', marginRight: '15px' }}>⚙️ Einstellungen</span>
<button onClick={handleLogout} className="nav-auth-button">Logout</button>
</>
) : (
<button onClick={() => history.push('/login')} className="nav-auth-button">Login</button>
)}
</div>
</Navbar>
);
}

Fazit

✅ Profil bearbeiten (Name, Nutzername, Newsletter)

✅ Passwort ändern

✅ Newsletter-Kategorien speichern

✅ Einstellungsseite in der Navbar erreichbar

Jetzt kann der Nutzer sein Profil verwalten! 🚀

Forgot Password Funktion

Hier ist die “Passwort vergessen”-Funktion, die es Nutzern ermöglicht, ihr Passwort per E-Mail zurückzusetzen.

1. Firebase: Passwort-Reset aktivieren

Falls noch nicht geschehen, stelle sicher, dass die Passwort-Zurücksetzen-Funktion in der Firebase Console aktiviert ist.

  1. Gehe zur Firebase Console.
  2. Authentication → Sign-in Method.
  3. Stelle sicher, dass “E-Mail/Passwort” aktiviert ist.
  4. Passwort-Reset-Seite (forgotPassword.tsx)

Erstelle die Datei src/pages/forgotPassword.tsx mit folgendem Inhalt:

import React, { useState } from 'react';
import { getAuth, sendPasswordResetEmail } from 'firebase/auth';
import { useHistory } from '@docusaurus/router';
import '../css/auth.css';

const ForgotPassword = () => {
const auth = getAuth();
const history = useHistory();
const [email, setEmail] = useState('');
const [message, setMessage] = useState('');

const handlePasswordReset = async (e: React.FormEvent) => {
e.preventDefault();
try {
await sendPasswordResetEmail(auth, email);
setMessage('Falls diese E-Mail existiert, wurde ein Link zum Zurücksetzen des Passworts gesendet.');
} catch (error) {
setMessage('Fehler beim Zurücksetzen des Passworts.');
}
};

return (
<div className="auth-container">
<h2>Passwort vergessen?</h2>
{message && <p className="auth-message">{message}</p>}

<form onSubmit={handlePasswordReset} className="auth-form">
<input
type="email"
placeholder="E-Mail-Adresse"
value={email}
onChange={(e) => setEmail(e.target.value)}
required
/>
<button type="submit">Passwort zurücksetzen</button>
</form>

<p>
<a href="/login">Zurück zum Login</a>
</p>
</div>
);
};

export default ForgotPassword;

2. Verlinkung in die Login-Seite (login.tsx)

Bearbeite src/pages/login.tsx, um einen Link zur “Passwort vergessen”-Seite hinzuzufügen.

Ändere den unteren Bereich:

<p>
<a href="/forgotPassword">Passwort vergessen?</a>
</p>
<p>
Noch kein Konto? <a href="/signup">Hier registrieren</a>
</p>

3. Styles für die “Passwort vergessen”-Seite (auth.css)

Füge diese Stile in src/css/auth.css hinzu, um die Seite ansprechend zu gestalten:

.auth-container {
max-width: 400px;
margin: 100px auto;
padding: 20px;
text-align: center;
background: #f6f8fa;
border-radius: 8px;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
}

.auth-message {
color: red;
font-size: 14px;
}

.auth-form {
display: flex;
flex-direction: column;
gap: 12px;
}

.auth-form input {
padding: 10px;
border: 1px solid #d1d5da;
border-radius: 6px;
font-size: 16px;
}

.auth-form button {
background-color: #2ea44f;
color: white;
font-size: 16px;
padding: 10px;
border-radius: 6px;
cursor: pointer;
font-weight: bold;
}

.auth-form button:hover {
background-color: #22863a;
}

4. Funktionsweise

✅ Nutzer gibt seine E-Mail-Adresse ein

✅ Firebase sendet eine Passwort-Zurücksetzen-E-Mail

✅ Nutzer erhält einen Link und kann sein Passwort ändern

✅ Rückkehr zur Login-Seite nach Absenden des Formulars

Nun ist die Passwort-Zurücksetzen-Funktion vollständig in deine Docusaurus-Seite mit Firebase integriert! 🚀