Skip to content

Conversation

@Tuntii
Copy link
Owner

@Tuntii Tuntii commented Jan 19, 2026

Description

Please include a summary of the changes and the related issue. Please also include relevant motivation and context.

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Refactoring (no functional changes)
  • Performance improvement
  • Test addition or update
  • CI/CD changes
  • Other (please describe):

Checklist

  • My code follows the project's style guidelines
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules

Related Issues

Fixes # (issue number)

Testing

Please describe the tests that you ran to verify your changes:

  • Unit tests
  • Integration tests
  • Manual testing
  • Other (please describe):

Screenshots (if applicable)

Add screenshots to help explain your changes.

Additional Notes

Add any other context about the pull request here.

Introduces CSRF protection using the Double-Submit Cookie pattern to the README, library docs, and cookbook. Adds a dedicated recipe for CSRF protection, updates feature tables, and provides configuration and usage examples for both backend and frontend integration.
Updated Cargo.toml and Cargo.lock to reference version 0.1.13 for all internal RustAPI crates. This ensures consistency across the workspace and prepares for the next release.
Copilot AI review requested due to automatic review settings January 19, 2026 01:25
@Tuntii Tuntii merged commit 410a7ff into main Jan 19, 2026
8 checks passed
github-actions bot pushed a commit that referenced this pull request Jan 19, 2026
…amework-ergonomics-update

Feature/framework ergonomics update 410a7ff
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request adds comprehensive documentation for CSRF protection functionality in the RustAPI framework. The changes introduce a new cookbook recipe explaining CSRF protection using the Double-Submit Cookie pattern, update feature documentation, and bump version numbers from 0.1.12 to 0.1.13.

Changes:

  • Added complete CSRF protection recipe documentation with examples and best practices
  • Updated feature tables and documentation in rustapi-extras crate and README
  • Bumped all crate versions from 0.1.12 to 0.1.13 in workspace configuration

Reviewed changes

Copilot reviewed 6 out of 7 changed files in this pull request and generated 15 comments.

Show a summary per file
File Description
docs/cookbook/src/recipes/csrf_protection.md New comprehensive CSRF protection recipe with configuration, integration examples, and security considerations
docs/cookbook/src/crates/rustapi_extras.md Added CSRF feature documentation with basic usage examples
docs/cookbook/src/SUMMARY.md Added CSRF Protection recipe to table of contents
crates/rustapi-extras/src/lib.rs Updated crate documentation to include CSRF feature and example
README.md Added csrf feature to feature table
Cargo.toml Version bump from 0.1.12 to 0.1.13 for all workspace crates
Cargo.lock Updated lock file to reflect version changes

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

let config = CsrfConfig::new()
// Cookie settings
.cookie_name("csrf_token") // Default: "csrf_token"
.cookie_path("/") // Default: "/"
Copy link

Copilot AI Jan 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method cookie_path() does not exist in the CsrfConfig implementation. There is no setter method for cookie_path in the config.rs file.

Suggested change
.cookie_path("/") // Default: "/"

Copilot uses AI. Check for mistakes.
Comment on lines +28 to +31
<form method="POST" action="/submit">
<input type="hidden" name="csrf_token" value="{}" />
<button type="submit">Submit</button>
</form>
Copy link

Copilot AI Jan 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This example is misleading. The CSRF middleware validates the token from the request header (X-CSRF-Token or the configured header name), not from form data. Including the token as a hidden input field in a traditional HTML form will not work with this middleware implementation. For HTML forms to work with this CSRF protection, JavaScript would be needed to read the cookie and include it as a header, or the form would need to be submitted via JavaScript/AJAX with the header included.

Suggested change
<form method="POST" action="/submit">
<input type="hidden" name="csrf_token" value="{}" />
<button type="submit">Submit</button>
</form>
<button id="submit-btn" type="button">Submit</button>
<script>
document.getElementById('submit-btn').addEventListener('click', async () => {{
const response = await fetch('/submit', {{
method: 'POST',
headers: {{
'X-CSRF-Token': '{}'
}}
}});
const text = await response.text();
alert(text);
}});
</script>

Copilot uses AI. Check for mistakes.
|--------------|--------|
| Token in cookie | ✅ HttpOnly=false (JS needs access) |
| Token validation | ✅ Constant-time comparison |
| SameSite cookie | ✅ Configurable (Strict by default) |
Copy link

Copilot AI Jan 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The default SameSite policy is incorrect. According to the implementation in config.rs line 55, the default is SameSite::Lax, not Strict.

Suggested change
| SameSite cookie | ✅ Configurable (Strict by default) |
| SameSite cookie | ✅ Configurable (Lax by default) |

Copilot uses AI. Check for mistakes.
| Consideration | Status |
|--------------|--------|
| Token in cookie | ✅ HttpOnly=false (JS needs access) |
| Token validation | ✅ Constant-time comparison |
Copy link

Copilot AI Jan 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation claims constant-time comparison is used for token validation, but the actual implementation at layer.rs line 73 uses a regular string equality check (h_token == token.as_str()), which is vulnerable to timing attacks. This should use a constant-time comparison function to prevent timing attacks that could leak information about the token.

Suggested change
| Token validation | ✅ Constant-time comparison |
| Token validation | Uses regular equality check (not constant-time in this example) |

Copilot uses AI. Check for mistakes.
```rust
let config = CsrfConfig::new()
// Cookie settings
.cookie_name("csrf_token") // Default: "csrf_token"
Copy link

Copilot AI Jan 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The default cookie name is incorrect. According to the actual implementation in crates/rustapi-extras/src/csrf/config.rs, the default cookie name is "XSRF-TOKEN", not "csrf_token".

Copilot uses AI. Check for mistakes.
Comment on lines +69 to +70
.header_name("X-CSRF-Token") // Default: "X-CSRF-Token"
.token_length(32); // Default: 32 bytes
Copy link

Copilot AI Jan 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method token_length() does not exist in the CsrfConfig implementation. There is no setter method for token_length in the config.rs file.

Suggested change
.header_name("X-CSRF-Token") // Default: "X-CSRF-Token"
.token_length(32); // Default: 32 bytes
.header_name("X-CSRF-Token"); // Default: "X-CSRF-Token"
// Token length is fixed at 32 bytes by default and is not configurable.

Copilot uses AI. Check for mistakes.
let csrf_config = CsrfConfig::new()
.cookie_name("csrf_token")
.header_name("X-CSRF-Token")
.cookie_secure(true); // HTTPS only
Copy link

Copilot AI Jan 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method name is incorrect. The actual method is secure(), not cookie_secure(). According to the implementation in config.rs, the builder method is named secure().

Suggested change
.cookie_secure(true); // HTTPS only
.secure(true); // HTTPS only

Copilot uses AI. Check for mistakes.
function getCsrfToken() {
return document.cookie
.split('; ')
.find(row => row.startsWith('csrf_token='))
Copy link

Copilot AI Jan 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This example assumes the cookie name is "csrf_token", but the actual default cookie name is "XSRF-TOKEN" according to the implementation. The cookie name should match what is configured or use the default.

Suggested change
.find(row => row.startsWith('csrf_token='))
.find(row => row.startsWith('XSRF-TOKEN='))

Copilot uses AI. Check for mistakes.
Comment on lines +96 to +103
For traditional form submissions, include the token as a hidden field:

```html
<form method="POST" action="/api/submit">
<input type="hidden" name="_csrf" value="{{ csrf_token }}" />
<!-- form fields -->
<button type="submit">Submit</button>
</form>
Copy link

Copilot AI Jan 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This example is misleading. The CSRF middleware validates the token from the request header, not from form data. A hidden input field with name="_csrf" will not be validated by the middleware as implemented. For traditional HTML forms to work with this CSRF protection, JavaScript is needed to intercept the form submission and add the token as a header.

Suggested change
For traditional form submissions, include the token as a hidden field:
```html
<form method="POST" action="/api/submit">
<input type="hidden" name="_csrf" value="{{ csrf_token }}" />
<!-- form fields -->
<button type="submit">Submit</button>
</form>
For traditional HTML form submissions, the CSRF middleware still expects the token in a request header (not in form data). Use JavaScript to intercept the submission, read the token, and send the request with the header:
```html
<form id="csrf-form" method="POST" action="/api/submit">
<!-- form fields -->
<button type="submit">Submit</button>
</form>
<script>
document.getElementById('csrf-form').addEventListener('submit', function (event) {
event.preventDefault();
const form = event.target;
const formData = new FormData(form);
// Read token from cookie (must match the cookie name set by the backend)
const csrfToken = document.cookie
.split('; ')
.find(row => row.startsWith('csrf_token='))
?.split('=')[1];
fetch(form.action, {
method: form.method,
body: formData,
headers: {
'X-CSRF-Token': csrfToken,
},
});
});
</script>

Copilot uses AI. Check for mistakes.
use cookie::SameSite;

let config = CsrfConfig::new()
.cookie_same_site(SameSite::Strict); // Most restrictive
Copy link

Copilot AI Jan 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method name is incorrect. The actual method is same_site(), not cookie_same_site(). According to the implementation in config.rs, the builder method is named same_site().

Suggested change
.cookie_same_site(SameSite::Strict); // Most restrictive
.same_site(SameSite::Strict); // Most restrictive

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants