roc-lang / roc-lang/basic-webserver
Add session-backed CSRF token generation and verification helpers
Nobody has claimed this yet.
- Dominant language
- HTML
- Stars
- 107
- Forks
- 20
- Avg merge
- 1d 17h
- Merged PRs (30d)
- 11
Description
Summary
Add a focused Csrf module implementing the synchronizer-token building blocks needed by HTML forms and browser APIs.
Illustrative API:
token = Csrf.generate!() # persist in the server-side session
form_value = token.to_str()
match Csrf.verify({
expected: Csrf.from_stored(session.csrf_token)?,
presented: submitted_value,
}) {
Valid => handle_state_change()
Invalid(reason) => forbidden(reason)
}
Dependencies
- #198 for OS-backed cryptographic random bytes
- #203 for the intended server-side session integration
- #199 for the surrounding session-cookie flow
Why this should not be generic middleware
CSRF enforcement depends on route semantics, authentication, and where the application obtains the submitted token. A form handler may need to parse a bounded URL-encoded or multipart body before verification, while a JSON endpoint normally reads a header.
Automatically consuming request bodies or guessing which methods and routes are safe would conflict with the explicit request-body and routing model. The platform should instead provide a difficult-to-misuse token type and verification function.
OWASP recommends server-generated, secret, unpredictable synchronizer tokens that are compared with session state. It also warns against placing synchronizer tokens in cookies, URLs, or logs.
Required contract
- Generate tokens from at least 32 bytes returned by
Random.bytes!. - Use a fixed cookie/form-safe representation with strict parsing.
- Make the token nominal and redact its normal inspection.
- Verify token values with a constant-time comparison after validating their fixed length and encoding.
- Distinguish missing, malformed, and mismatched tokens.
- Provide a helper for extracting exactly one configured request header without consuming the body.
- Form handlers parse their own bounded body and pass the presented value explicitly.
- Document that the application stores the expected token in its server-side session.
- Rotate the token on session creation, authentication, and session-identifier rotation.
- Never emit token values in error messages, access logs, or metrics.
- Provide an end-to-end form example using the SQLite session facility.
Non-goals
- Automatic protection of all
POSTrequests - Guessing safe routes or methods
- Consuming form or multipart bodies behind the application
- CORS policy
- A naive double-submit cookie design
- Stateless signed tokens or general HMAC APIs
- Origin/Referer validation based on untrusted forwarded headers
Acceptance criteria
- Applications can generate, persist, render, and verify synchronizer tokens.
- Verification uses fixed-format parsing and constant-time comparison.
- Missing, malformed, and mismatched values are distinguishable without leaking secrets.
- Header extraction never consumes the request body.
- A real-listener example demonstrates session cookie plus protected form submission.
References
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reading the linked dependency issues #198, #203, and #199, then trace the SQLite session facility and its real-listener example. Done means applications can generate, store, render, and verify fixed-format synchronizer tokens, distinguish failure cases without leaks, extract a header without consuming the body, and demonstrate a protected form submission.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- sqlite
- Domain
- backend-api-design, security
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100