run-what 1.3.0

HTML-first web framework powered by Rust. No JavaScript frameworks, no build steps—just HTML.
<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>&lt;if user.authenticated&gt;
  Welcome, #user.full_name#!
  &lt;a href="/dashboard"&gt;Dashboard&lt;/a&gt;
  &lt;else/&gt;
  &lt;a href="/login"&gt;Log in&lt;/a&gt;
&lt;/if&gt;

&lt;if user.role == admin&gt;
  &lt;a href="/admin"&gt;Admin Panel&lt;/a&gt;
&lt;/if&gt;</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#) &mdash; 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>&lt;what&gt;</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>&lt;!-- Public page --&gt;
&lt;what&gt;
auth: all
&lt;/what&gt;

&lt;!-- Any logged-in user --&gt;
&lt;what&gt;
auth: user
&lt;/what&gt;

&lt;!-- Admin or editor only --&gt;
&lt;what&gt;
auth: admin, editor
&lt;/what&gt;</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>&lt;!-- Login form --&gt;
&lt;form method="post" action="/w-auth/login"&gt;
  &lt;input name="email" type="email" w-required&gt;
  &lt;input name="password" type="password" w-required&gt;
  &lt;button type="submit"&gt;Log in&lt;/button&gt;
&lt;/form&gt;

&lt;!-- Logout button --&gt;
&lt;form method="post" action="/w-auth/logout"&gt;
  &lt;button type="submit"&gt;Log out&lt;/button&gt;
&lt;/form&gt;</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>&lt;if user.authenticated&gt;</code> for conditional UI</li>
      <li><code>auth: user</code> / <code>auth: admin, editor</code> in <code>&lt;what&gt;</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>