CSRF

CSRF protection — Prisme, POST-to-handler contract.

● ● ●
// Every POST form must go through Prisme<T>
// Prisme validates the CSRF token before entering the handler.
pub async fn registration(
    mut request: Request,
    Prisme(mut form): Prisme<RegisterForm>,
) -> AppResult<Response> {
    if request.is_post() && form.is_valid().await {
        // Secure processing — CSRF has been validated
        return Ok(Redirect::to("/profile").into_response());
    }
    context_update!(request => { "form" => &form });
    request.render("auth/registration.html")
}
<form method="POST" action="{% link "registration" %}">
    {# Full render — CSRF included automatically #}
    {% form.registration_form %}
    <button type="submit">Sign up</button>
</form>

{# Field-by-field render — CSRF always included automatically #}
<form method="POST" action="{% link "registration" %}">
    {% form.registration_form.username %}
    {% form.registration_form.password %}
    <button type="submit">Sign up</button>
</form>
// GET  → token generated, stored in session, injected into Tera context
// POST → Prisme extracts the token from the body, compares in constant-time
//        (via subtle::ConstantTimeEq to prevent timing attacks)

// If the token is invalid or missing:
//   → empty form + CSRF error message
//   → the handler is never executed

// The token is tied to the session — it changes with each new session.