feat(auth): OPTIONAL_AUTH route level across all service macros#23
Merged
Conversation
Adds a third auth level, OPTIONAL_AUTH, to rest_service!, file_service!,
jsonrpc_service!, and jsonrpc_bidirectional_service!. An OPTIONAL_AUTH route is
public — never rejected for auth reasons — but opportunistically identifies its
caller: the handler receives a ras_auth_core::Caller (Anonymous /
Authenticated(user)) as its first argument (file_service surfaces it through the
existing FileRequestContext). Resolution is fully lenient: a missing, invalid,
or expired credential, or a cookie that fails CSRF on an unsafe method, resolves
to Caller::Anonymous rather than a 401/403.
- ras-auth-core: new #[must_use] Caller enum, non-rejecting resolve_caller
resolver, and From<Option<AuthenticatedUser>>.
- ras-permission-manifest: new AuthRequirementInfo::Optional variant;
SCHEMA_VERSION bumped 1 -> 2.
- OpenAPI emits an optional security requirement ([{}, {bearerAuth: []}]);
OpenRPC emits x-authentication { required: false } for optional operations.
- OPTIONAL_AUTH on bidirectional server_to_client calls is a hard parse error
(there is no inbound caller to deliver).
- Existing UNAUTHORIZED / WITH_PERMISSIONS behavior is unchanged; new e2e tests
cover every macro, including the versioned/legacy REST handler arm.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
anyhow 1.0.102 is flagged by RUSTSEC-2026-0190 (unsoundness in Error::downcast_mut after Error::context). Update to the patched 1.0.103 to keep the supply-chain policy (cargo-deny advisories) green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
bb15796 to
dd7410f
Compare
…o docs Threads the new OPTIONAL_AUTH / Caller level through every place the existing auth levels were documented: - documentation/ (mdBook): auth-in-api-contract.md gets a full OPTIONAL_AUTH + Caller section and the optional-security note; the four macro pages and the contract tutorial list the third level and the Caller/FileRequestContext handler shapes. - Crate READMEs (rest, file, jsonrpc, jsonrpc-core, bidirectional) and the top-level README: OPTIONAL_AUTH example lines; the jsonrpc-macro feature bullet now lists all three levels. - file_service! gains a doc comment; the bidirectional macro doc comment and the internal parser comments now mention OPTIONAL_AUTH. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
159c2cd to
8c5f6ec
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds a third auth level,
OPTIONAL_AUTH, to all four service macros (rest_service!,file_service!,jsonrpc_service!,jsonrpc_bidirectional_service!).RAS endpoints were previously binary:
UNAUTHORIZED(no caller, ever) orWITH_PERMISSIONS([...])(caller required, else 401). There was no way to express "anonymous is allowed, but if a valid credential is present, identify the caller and hand it to the handler" — a common "public but richer when signed in" shape (per-document ACLs, personalization, author-preview).An
OPTIONAL_AUTHroute is public — never rejected for auth reasons — but opportunistically identifies its caller. The handler receives aras_auth_core::Calleras its first argument:Design
Callerenum, notunsafe— the footgun (easy to forget the anonymous case) is handled with a self-describing,#[must_use]type passed as an explicit parameter, not by abusingunsafe(which is a memory-safety marker, would break downstream#![forbid(unsafe_code)], and enforces nothing).Caller::Anonymousrather than a 401/403. A forged/stale credential simply executes as the public path.resolve_callerinras-auth-coreis the non-rejecting counterpart toauthorize_request, reusing the same credential/CSRF/authenticate plumbing.FileRequestContext(alreadyOption<&AuthenticatedUser>) rather than changing its handler signature.OPTIONAL_AUTHon outboundserver_to_clientcalls is a hard parse error (no inbound caller to deliver).Changes
ras-auth-core:Callerenum,resolve_caller,From<Option<AuthenticatedUser>>.ras-permission-manifest: newAuthRequirementInfo::Optional;SCHEMA_VERSIONbumped 1 → 2 (older pinned consumers will fail to deserialize"type":"optional").security: [{}, {bearerAuth: []}]; OpenRPC emitsx-authentication { required: false }.ras-auth-coreREADME, and CHANGELOG updated.Compatibility
Existing
UNAUTHORIZED/WITH_PERMISSIONSbehavior is unchanged.Tests
New e2e coverage in every macro (anonymous / valid-token / invalid-token-lenient), including the versioned/legacy REST handler arm and a parse-rejection test for
OPTIONAL_AUTHon bidirectionalserver_to_clientcalls.cargo build --workspace✓cargo clippy --workspace --all-targets✓ (zero warnings)🤖 Generated with Claude Code