Refactor AuthenticationMiddleware so each Authenticator applies itself (#290)#294
Conversation
…290) Replaces the per-method switch in AuthenticationMiddleware with a public Authenticator protocol whose concrete types own both the credential payload and the rules for attaching it to a request. The middleware now resolves to a single delegation call. - Adds public Authenticator protocol + APITokenAuthenticator, WebAuthTokenAuthenticator, ServerToServerAuthenticator - Replaces TokenManager.getCurrentCredentials() with currentAuthenticator() - ServerToServerAuthenticator owns request signing, killing the manager downcast and assertionFailure in the middleware. Buffers body once and reassigns it so downstream sees the same bytes regardless of HTTPBody iteration behavior. Exposes configurable bodyBufferLimit. - Format validation moves into authenticator throwing inits - Each authenticator owns its wire format via encoded()/init(decoding:); InMemoryTokenStorage routes decoding by storageKey - Deletes AuthenticationMethod, TokenCredentials, ServerToServerAuthManager+RequestSigning, and obsolete tests - Adds dedicated per-authenticator test suites Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Code Review — PR #294: Refactor AuthenticationMiddleware so each Authenticator applies itselfOverall: Strong architectural improvement. The middleware collapse to a one-liner, the elimination of ✅ What's good
🐛 Bug / Naming issue:
|
Code Review — PR #294: Refactor AuthenticationMiddleware so each Authenticator applies itselfOverviewThis is a well-executed architectural refactor. Pushing request-mutation logic from the middleware (which had to switch over Issues1. Silent body-buffering failure in
|
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## v1.0.0-beta.1 #294 +/- ##
==================================================
+ Coverage 25.66% 66.04% +40.38%
==================================================
Files 95 480 +385
Lines 8240 13513 +5273
==================================================
+ Hits 2115 8925 +6810
+ Misses 6125 4588 -1537
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Code Review (Draft)OverviewLarge refactor (~1500 additions / ~1700 deletions) pushing per-method authentication logic from Code QualityPositive:
Issues:
Test CoverageTests for A test verifying that SummaryArchitecture direction is correct. Before marking ready: fix the |
Code Review — PR #294: Refactor
|
- ServerToServerAuthenticator.authenticate now propagates HTTPBody.collecting errors instead of silently signing over an empty body. An oversized body throws rather than producing a request that CloudKit will reject with a signature mismatch. - Add defaultStorageIdentifier requirement to Authenticator (default returns storageKey). Each concrete type provides a richer identifier; deletes the type-switch in InMemoryTokenStorage+Convenience that bypassed the protocol abstraction. - Document that Authenticator.encoded() may contain sensitive credential material so TokenStorage implementors handle persistence accordingly. - Drop the redundant test-sign in ServerToServerAuthenticator.init — a successfully-parsed P256.Signing.PrivateKey is by definition capable of signing, and this ran on every per-request currentAuthenticator() call. - Rename HTTPRequest.appendingQueryItems → appendQueryItems (mutating methods take the imperative form). - Bump swift-crypto to 4.0.0 so P256.Signing.PrivateKey conforms to Sendable on Linux (fixes the CI build failure on the Sendable-conforming class diagnostic). Adds tests for oversized-body throw and defaultStorageIdentifier per type. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Reorder authenticator types to match SwiftLint's type_contents_order (subtype → type_property → instance_property → initializer → other_method). Move private WireFormat to top of each struct, place init(decoding:) with other initializers. - Split ServerToServerAuthenticator.signRequest into its own +Signing.swift extension to keep the main file under SwiftLint's 225-line limit. - Move S2S manager's privateKeyData computed property up before its initializers. - Add doc comments to all protocol witnesses on the new authenticator types and InMemoryTokenStorage's TokenStorage methods. - Add - Throws sections to Authenticator.authenticate and ServerToServerAuthenticator.signRequest. - Drop redundant `as TokenManagerError` casts in catch clauses — the inits use typed throws so the cast is always-true. - Downgrade unused public Foundation import in WebAuthTokenManager+Methods to internal. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Code Review: Authenticator Protocol Refactor (#294)OverviewThis PR pushes per-method authentication logic out of Strengths
IssuesMedium1.
2. The factory map is a static private static let factories: [String: @Sendable (Data) throws -> any Authenticator] = { ... }()
3. Remaining manager downcast in The middleware downcast was eliminated, but if let serverManager = tokenManager as? ServerToServerAuthManager {
keyID = serverManager.keyID
privateKeyData = serverManager.privateKeyDataIf the intent is to fully remove downcasts, this one was missed. If it's intentional (different code path), a comment explaining why the Minor4.
5. Error-checking test pattern could use The new authenticator tests check error types via do {
_ = try APITokenAuthenticator(token: "")
Issue.record("Expected init to throw")
} catch {
if case .invalidCredentials(.apiTokenEmpty) = error { ... }
else { Issue.record("Unexpected error: \(error)") }
}Swift Testing's 6.
Security7. Raw P-256 key material in JSON.
SummaryThe refactor is well-executed. The middleware is genuinely simpler and the body-buffering bug fix is a real correctness win. The main actionable items are:
The test count increase (18 new tests) and the explicit body-buffering regression test make this feel well-covered. Approve with the above for consideration. 🤖 Reviewed with Claude Code |
Summary
Closes #290.
AuthenticationMiddleware.interceptpreviously owned all per-method knowledge of how to attach credentials — switching overTokenCredentials.methodand reaching back intotokenManager as? ServerToServerAuthManagerfor signing. This PR pushes the request-mutation logic onto the credential itself.Changes
Authenticatorprotocol withstorageKey,authenticate(request:body:),encoded(),init(decoding:). Existential-friendly — noSelfrequirement (Equatable/Codabledeliberately not inherited). Consumers can write custom auth (test fakes, future modes) without forking MistKit.APITokenAuthenticator,WebAuthTokenAuthenticator,ServerToServerAuthenticator. Each owns format validation in itsthrowsinit and its on-disk wire format.authenticate→ forward. No switch, no downcast, noassertionFailure.TokenManager.getCurrentCredentials()→currentAuthenticator() -> (any Authenticator)?on the protocol and all four managers (APITokenManager,WebAuthTokenManager,ServerToServerAuthManager,AdaptiveTokenManager).ServerToServerAuthenticatorowns signing — kills the manager downcast and theassertionFailure. Buffers the body once and reassigns it viabody: inout HTTPBody?so downstream middleware sees the same bytes regardless ofHTTPBodyiteration behavior. Exposes configurablebodyBufferLimit(default 1 MiB).TokenStoragenow storesany Authenticator;InMemoryTokenStorageuses[storageKey: Data]with a factory map for routing decoding.AuthenticationMethod,TokenCredentials,ServerToServerAuthManager+RequestSigning,credentialsWithMetadata(_:)on each manager,validateAPITokenFormat/validateWebAuthTokenFormatstatic helpers, and the now-redundantInternalErrorReason.serverToServerRequiresSpecificManager/failedCredentialRetrieval{AfterUpgrade,AfterDowngrade}cases.APITokenAuthenticatorTests,WebAuthTokenAuthenticatorTests,ServerToServerAuthenticatorTestscover per-method query/header construction, format validation throwing from init, andencoded()↔init(decoding:)round-trip. The S2S suite includes a regression test for body re-buffering on.singleiteration bodies.No deprecation cycle — pre-1.0, dropped in one PR per the issue's recommendation.
Test plan
swift test— 430 tests / 127 suites pass (up from 412)cd Examples/MistDemo && swift test— 831 tests / 275 suites pass🤖 Generated with Claude Code
Perform an AI-assisted review on