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
72 lines
3.2 KiB
HTML
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>© 2026 patholo — 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}}
|