<what>
title: "Step 9 — Authentication"
active_step: 9
</what>
<h1 class="text-3xl font-bold mb-2" style="color: #111827; letter-spacing: -0.02em;">Step 9 — Authentication</h1>
<p class="text-gray-500 text-sm mb-8">JWT auth, role-based access control, all declared in HTML.</p>
<section class="mb-8">
<h2 class="text-lg font-semibold mb-3" style="color: #111827;">How auth works</h2>
<p class="text-gray-600 mb-4" style="line-height: 1.7;">
wwwhat uses JWT tokens stored in a cookie. When a user logs in via <code>POST /w-auth/login</code>, the server issues a JWT containing their <code>user_id</code>, <code>email</code>, <code>full_name</code>, and <code>role</code>. Every subsequent request is verified against this token.
</p>
<div class="card mb-4">
<div class="card-body">
<div class="text-sm font-semibold text-gray-700 mb-3">JWT Cookie contents</div>
<pre class="bg-gray-50 p-3 rounded text-sm font-mono" style="border: 1px solid #e5e7eb; margin: 0;"><code>{
"user_id": 42,
"email": "jane@example.com",
"full_name": "Jane Smith",
"role": "admin"
}</code></pre>
</div>
</div>
</section>
<section class="mb-8">
<h2 class="text-lg font-semibold mb-3" style="color: #111827;">Configuring auth in wwwhat.toml</h2>
<pre class="bg-gray-50 p-4 rounded text-sm font-mono" style="border: 1px solid #e5e7eb; overflow-x: auto;"><code>[auth]
enabled = true
jwt_secret = "your-secret-key-here"
cookie_name = "w_auth"
expiry_days = 7</code></pre>
</section>
<section class="mb-8">
<h2 class="text-lg font-semibold mb-3" style="color: #111827;">User variables in templates</h2>
<p class="text-gray-600 mb-3" style="line-height: 1.7;">
When a user is logged in, these variables are available in all templates:
</p>
<div class="card mb-4">
<div class="card-body" style="padding: 0;">
<table style="width: 100%; border-collapse: collapse; font-size: 0.875rem;">
<thead>
<tr style="background: #f9fafb; border-bottom: 1px solid #e5e7eb;">
<th style="text-align: left; padding: 0.75rem 1rem; font-weight: 600; color: #374151;">Variable</th>
<th style="text-align: left; padding: 0.75rem 1rem; font-weight: 600; color: #374151;">Value</th>
</tr>
</thead>
<tbody>
<tr style="border-bottom: 1px solid #f3f4f6;">
<td style="padding: 0.625rem 1rem;"><code>#user.authenticated#</code></td>
<td style="padding: 0.625rem 1rem; color: #6b7280;"><code>true</code> or empty</td>
</tr>
<tr style="border-bottom: 1px solid #f3f4f6;">
<td style="padding: 0.625rem 1rem;"><code>#user.email#</code></td>
<td style="padding: 0.625rem 1rem; color: #6b7280;">jane@example.com</td>
</tr>
<tr style="border-bottom: 1px solid #f3f4f6;">
<td style="padding: 0.625rem 1rem;"><code>#user.full_name#</code></td>
<td style="padding: 0.625rem 1rem; color: #6b7280;">Jane Smith</td>
</tr>
<tr>
<td style="padding: 0.625rem 1rem;"><code>#user.role#</code></td>
<td style="padding: 0.625rem 1rem; color: #6b7280;">admin, editor, user, etc.</td>
</tr>
</tbody>
</table>
</div>
</div>
</section>
<section class="mb-8">
<h2 class="text-lg font-semibold mb-3" style="color: #111827;">Conditional UI based on auth</h2>
<p class="text-gray-600 mb-3" style="line-height: 1.7;">
Show and hide content based on whether the user is logged in or their role.
</p>
<pre class="bg-gray-50 p-4 rounded text-sm font-mono" style="border: 1px solid #e5e7eb; overflow-x: auto;"><code><if user.authenticated>
Welcome, #user.full_name#!
<a href="/dashboard">Dashboard</a>
<else/>
<a href="/login">Log in</a>
</if>
<if user.role == admin>
<a href="/admin">Admin Panel</a>
</if></code></pre>
<div class="card mt-4">
<div class="card-body">
<div class="text-sm font-semibold text-gray-700 mb-3">Live example (your current auth state)</div>
<if user.authenticated>
<div style="background: #f0fdf4; border: 1px solid #bbf7d0; border-radius: 0.5rem; padding: 0.75rem 1rem; font-size: 0.875rem; color: #166534;">
Logged in as <strong>#user.full_name#</strong> (#user.email#) — role: <strong>#user.role|default:"user"#</strong>
</div>
</if>
<unless user.authenticated>
<div style="background: #f9fafb; border: 1px solid #e5e7eb; border-radius: 0.5rem; padding: 0.75rem 1rem; font-size: 0.875rem; color: #6b7280;">
Not logged in. Auth is not configured in this tutorial project.
</div>
</unless>
</div>
</div>
</section>
<section class="mb-8">
<h2 class="text-lg font-semibold mb-3" style="color: #111827;">Protecting pages with auth directives</h2>
<p class="text-gray-600 mb-3" style="line-height: 1.7;">
Set <code>auth:</code> in the page's <code><what></code> block to restrict access. Unauthenticated requests redirect to <code>/login</code>.
</p>
<pre class="bg-gray-50 p-4 rounded text-sm font-mono" style="border: 1px solid #e5e7eb; overflow-x: auto;"><code><!-- Public page -->
<what>
auth: all
</what>
<!-- Any logged-in user -->
<what>
auth: user
</what>
<!-- Admin or editor only -->
<what>
auth: admin, editor
</what></code></pre>
<p class="text-sm text-gray-500 mt-2">
You can also set <code>auth: user</code> in <code>application.what</code> to protect an entire directory at once.
</p>
</section>
<section class="mb-8">
<h2 class="text-lg font-semibold mb-3" style="color: #111827;">Login and logout</h2>
<pre class="bg-gray-50 p-4 rounded text-sm font-mono" style="border: 1px solid #e5e7eb; overflow-x: auto;"><code><!-- Login form -->
<form method="post" action="/w-auth/login">
<input name="email" type="email" w-required>
<input name="password" type="password" w-required>
<button type="submit">Log in</button>
</form>
<!-- Logout button -->
<form method="post" action="/w-auth/logout">
<button type="submit">Log out</button>
</form></code></pre>
<p class="text-sm text-gray-500 mt-2">
Successful login redirects to the <code>redirect</code> form field value, or <code>/</code> by default.
</p>
</section>
<div class="card" style="border-color: #bbf7d0; background: #f0fdf4;">
<div class="card-body">
<div class="text-sm font-semibold mb-2" style="color: #14532d;">What you learned</div>
<ul class="text-sm space-y-1" style="color: #166534; padding-left: 1.25rem; list-style: disc;">
<li>Auth uses JWT cookies — configure in <code>wwwhat.toml</code> under <code>[auth]</code></li>
<li>User variables: <code>#user.authenticated#</code>, <code>#user.email#</code>, <code>#user.full_name#</code>, <code>#user.role#</code></li>
<li><code><if user.authenticated></code> for conditional UI</li>
<li><code>auth: user</code> / <code>auth: admin, editor</code> in <code><what></code> blocks protects pages</li>
<li>Login: <code>POST /w-auth/login</code> — Logout: <code>POST /w-auth/logout</code></li>
<li>Set <code>auth:</code> in <code>application.what</code> to protect entire directories</li>
</ul>
</div>
</div>