Files
paliad/templates/login.html
m 21bf56dc20 feat: add Supabase password auth with @hoganlovells.com restriction
Go server authenticates against Supabase GoTrue (youpc instance) using
email+password. Login page with login/register tabs, domain restricted
to @hoganlovells.com. Auth middleware protects all routes, refreshes
expired tokens via refresh_token cookie. Lime green branding.

- internal/auth: Supabase client (sign in, sign up, refresh, sign out),
  JWT expiry decode, auth middleware, cookie management
- internal/handlers: login/register/logout handlers, per-page template
  parsing to avoid content block collisions
- templates/login.html: tabbed login/register form
- 30-day HTTP-only session cookies with SameSite=Lax
- SUPABASE_URL and SUPABASE_ANON_KEY env vars in docker-compose
2026-04-14 16:34:17 +02:00

72 lines
3.2 KiB
HTML

{{define "login.html"}}
{{template "base" .}}
{{end}}
{{define "content"}}
<header class="header">
<div class="container">
<nav class="nav">
<a href="/" class="logo">
<span class="logo-mark">p</span>
<span class="logo-text">patholo</span>
</a>
</nav>
</div>
</header>
<main class="login-main">
<div class="login-card">
<div class="login-tabs">
<button class="login-tab{{if ne .Mode "register"}} active{{end}}" data-tab="login">Anmelden</button>
<button class="login-tab{{if eq .Mode "register"}} active{{end}}" data-tab="register">Registrieren</button>
</div>
{{if .Error}}
<div class="login-error">{{.Error}}</div>
{{end}}
{{if .Success}}
<div class="login-success">{{.Success}}</div>
{{end}}
<form method="POST" action="/login" class="login-form" id="login-form"{{if eq .Mode "register"}} style="display:none"{{end}}>
<label for="login-email" class="login-label">E-Mail</label>
<input type="email" id="login-email" name="email" value="{{.Email}}" placeholder="name@hoganlovells.com" required autofocus class="login-input">
<label for="login-password" class="login-label">Passwort</label>
<input type="password" id="login-password" name="password" placeholder="Passwort" required class="login-input">
<button type="submit" class="login-button">Anmelden</button>
</form>
<form method="POST" action="/register" class="login-form" id="register-form"{{if ne .Mode "register"}} style="display:none"{{end}}>
<label for="reg-email" class="login-label">E-Mail</label>
<input type="email" id="reg-email" name="email" value="{{.Email}}" placeholder="name@hoganlovells.com" required class="login-input">
<label for="reg-password" class="login-label">Passwort</label>
<input type="password" id="reg-password" name="password" placeholder="Mind. 8 Zeichen" required minlength="8" class="login-input">
<label for="reg-confirm" class="login-label">Passwort bestätigen</label>
<input type="password" id="reg-confirm" name="confirm" placeholder="Passwort wiederholen" required minlength="8" class="login-input">
<button type="submit" class="login-button">Registrieren</button>
</form>
<p class="login-hint">Nur für @hoganlovells.com Adressen.</p>
</div>
</main>
<footer class="footer">
<div class="container">
<p>&copy; 2026 patholo &mdash; Internal use only. Hogan Lovells Patent Practice.</p>
</div>
</footer>
<script>
document.querySelectorAll('.login-tab').forEach(function(btn) {
btn.addEventListener('click', function() {
document.querySelectorAll('.login-tab').forEach(function(t) { t.classList.remove('active'); });
btn.classList.add('active');
document.getElementById('login-form').style.display = btn.dataset.tab === 'login' ? '' : 'none';
document.getElementById('register-form').style.display = btn.dataset.tab === 'register' ? '' : 'none';
document.querySelectorAll('.login-error, .login-success').forEach(function(el) { el.style.display = 'none'; });
});
});
</script>
{{end}}