mirror of
https://github.com/Comfy-Org/comfy-swift-sdk.git
synced 2026-11-04 23:47:26 +00:00
[PR #34] [MERGED] feat(auth): add ComfyAuthKit — default ASWebAuth presenter + Keychain token store (BE-2452) #38
Labels
No labels
enhancement
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Comfy-Org/comfy-swift-sdk#38
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
📋 Pull Request Information
Original PR: https://github.com/Comfy-Org/comfy-swift-sdk/pull/34
Author: @mattmillerai
Created: 7/7/2026
Status: ✅ Merged
Merged: 7/7/2026
Merged by: @mattmillerai
Base:
main← Head:matt/be-2452-comfyauthkit-defaults📝 Commits (1)
a02216cfeat(auth): add ComfyAuthKit — default ASWebAuth presenter + Keychain token store (BE-2452)📊 Changes
6 files changed (+727 additions, -2 deletions)
View changed files
📝
Package.swift(+11 -2)📝
README.md(+35 -0)➕
Sources/ComfyAuthKit/ASWebAuthPresenter.swift(+153 -0)➕
Sources/ComfyAuthKit/KeychainTokenStore.swift(+269 -0)➕
Tests/ComfyAuthKitTests/ASWebAuthPresenterTests.swift(+97 -0)➕
Tests/ComfyAuthKitTests/KeychainTokenStoreTests.swift(+162 -0)📄 Description
ELI-5
The SDK on its own knows the whole "Sign in with Comfy" dance except two app-shaped chores: popping the browser sheet and stashing the tokens in the Keychain. Today an app has to hand-write both. This adds a small second package,
ComfyAuthKit, that ships the obvious defaults for those two chores — a ready-made browser presenter and a Keychain token store — so an app can sign in with one call instead of a page of boilerplate. Apps that want full control still just useComfySwiftSDKand plug in their own. The defaults live in a separate target so they canimport AuthenticationServices/Securitywithout breaking the core SDK's Foundation-only rule.What & why
Implements BE-2452. Two-tier auth story:
ComfySwiftSDK(core) — Foundation-only, inject your ownComfyWebAuthPresenter/ComfyTokenStore.ComfyAuthKit(new) — batteries-included defaults, allowed to importAuthenticationServices+Security.Changes
Package.swift— add.library/.targetComfyAuthKit(depends onComfySwiftSDK) +ComfyAuthKitTests. Platforms unchanged (iOS 17+/macOS 14+).Sources/ComfyAuthKit/ASWebAuthPresenter.swift—@MainActor public final class ASWebAuthPresenter: NSObject, ComfyWebAuthPresenter, ASWebAuthenticationPresentationContextProviding. Ports the present-and-retain + cancellation mapping from Comfy-iOSOAuthCoordinator, narrowed to theComfyWebAuthPresenter.authenticate(url:callbackURLScheme:)contract (returns the callback URL unchanged; the SDK doesstateverification/code extraction).prefersEphemeralWebBrowserSession = false;.canceledLogin→ComfyError.authCancelled; optionalanchor:override, elseASPresentationAnchor()(iOS 17+ auto-locates the key window). Cancellation mapping is extracted to anonisolated static mapCallback(url:error:)so it's unit-testable without a real session.Sources/ComfyAuthKit/KeychainTokenStore.swift—public struct KeychainTokenStore: ComfyTokenStore. Ports the 3 OAuth slots +SecItem*helpers from Comfy-iOSKeychainStore, usingkSecAttrAccessibleAfterFirstUnlockThisDeviceOnly(background reattach reads while locked). Configurableservicefor test isolation;load()/save()/clear()map to the slots; never logs tokens;load()is all-or-nothing (a partial triple →nil).KeychainTokenStoreround-trip under a UUID-keyed service.README.md— documents the two tiers.Stacked PR
Based on
matt/be-2451-signin-orchestrator(#33), which itself stacks on #32 → #31. Those three children define theComfyWebAuthPresenter/ComfyTokenStore/ComfyStoredTokensprotocols andComfyError.authCancelledthat this PR builds on. Per the always-stack policy I built on the stack tip rather than waiting. Review/merge order: #31 → #32 → #33 → this. GitHub will retarget this PR tomainas the children merge.Testing
swift build+swift testgreen: 224 tests, 0 failures. The untouchedImportBoundaryTestsstill passes — confirming ComfyAuthKit'sAuthenticationServices/Securityimports do not trip the core-target scan (the whole point of the separate product).Judgment calls
.enabled(if: keychainAvailable)— a headless/unsigned test host (e.g. a plainswift testwith no usable login keychain) can't add generic-password items, so those tests skip rather than fail; the conformance/compile + value-isolation coverage runs everywhere, and the round-trip runs for real on a provisioned host (simulator / CI with an unlocked keychain). This is what keeps CI green without weakening the store.service. The three OAuth slots use fixed account keys (namespaced constants), so a UUID-keyedserviceis the isolation seam; a separate per-instanceaccountwould be redundant for a 3-slot store and isn't ported from the reference (that param was for the legacy API-key slot, which this store does not include).mapCallback— when a callback arrives with both a URL and an error, the error wins (matches the referenceOAuthCoordinator), so a failed session can't be mistaken for success. Documented with a test.🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.