mirror of
https://github.com/Comfy-Org/comfy-swift-sdk.git
synced 2026-11-04 23:47:26 +00:00
[PR #31] [MERGED] feat(auth): parameterize OAuth client config + add callback state-verification helper #32
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#32
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/31
Author: @mattmillerai
Created: 7/5/2026
Status: ✅ Merged
Merged: 7/7/2026
Merged by: @mattmillerai
Base:
main← Head:matt/be-2449-oauth-client-config📝 Commits (2)
c2ae295feat(auth): parameterize OAuth client config + add callback state-verification helperc1ca10cfix(auth): thread OAuthClientConfig through refresh + tighten callback checks📊 Changes
13 files changed (+422 additions, -69 deletions)
View changed files
📝
Sources/ComfySwiftSDK/Internal/Auth/OAuthConfiguration.swift(+4 -12)📝
Sources/ComfySwiftSDK/Internal/Auth/OAuthExchanger.swift(+7 -3)📝
Sources/ComfySwiftSDK/Internal/Auth/OAuthTokenRefreshExecutor.swift(+9 -2)📝
Sources/ComfySwiftSDK/Internal/PollingFallback.swift(+2 -2)📝
Sources/ComfySwiftSDK/Internal/SDKLog.swift(+2 -0)📝
Sources/ComfySwiftSDK/Internal/Transport.swift(+9 -2)📝
Sources/ComfySwiftSDK/Public/ComfyCloudClient.swift(+42 -17)📝
Sources/ComfySwiftSDK/Public/ComfyError.swift(+11 -0)📝
Sources/ComfySwiftSDK/Public/OAuthAuthorizationRequest.swift(+43 -1)➕
Sources/ComfySwiftSDK/Public/OAuthClientConfig.swift(+78 -0)➕
Tests/ComfySwiftSDKTests/OAuthClientConfigTests.swift(+176 -0)📝
Tests/ComfySwiftSDKTests/OAuthConfigurationTests.swift(+2 -29)📝
Tests/ComfySwiftSDKTests/OAuthExchangeTests.swift(+37 -1)📄 Description
ELI-5
The SDK's "Sign in with Comfy" code had the iOS app's identity (client id, redirect URL, scopes) baked in as constants, so no other app could reuse it. This makes those values a small
OAuthClientConfigvalue you pass in — defaulting to the exact iOS values, so nothing existing changes. It also adds one SDK helper,extractCode(fromCallback:), for the security check every app was copy-pasting: confirm the callback'sstatematches the one we sent (CSRF defense) and that there's a real code, before redeeming it.What changed
public struct OAuthClientConfig: Sendable(clientId,redirectScheme,redirectURI,scopes: [String]) withstatic let comfyIOScarrying today's exact hardcoded values. Shared protocol endpoints (issuer / authorize / token / metadata) stay in the internalOAuthConfiguration.buildAuthorizationRequest(config:)andexchangeAuthorizationCode(_:codeVerifier:config:)now take a config defaulting to.comfyIOS. Existing no-arg / two-arg call sites keep compiling and behave identically.OAuthAuthorizationRequest.extractCode(fromCallback:)— ports the app'sparseCallbackstate-verification into the SDK: parsescode+state, rejects an empty/missingcode, and requiresstate == self.state.ComfyError.authStateMismatchand.authCancelledadded and documented (DocC); wired into the two exhaustiveComfyErrorswitches (PollingFallback.isTransient,SDKLogcase-name mapper — both treat them as non-transient, and the mapper only ever emits the case name, never a secret).oauthCallbackSchemestatic now sources the comfyIOS default from the config; unchanged value (org.comfy.ios).Tests
New
OAuthClientConfigTests+ updates:client_id/redirect_uri/scopesfor a custom config;extractCodematrix: valid, empty code, missing code, missing state, and state-mismatch →.authStateMismatch;comfyIOSequals the prior hardcoded values (client id, scheme, redirect URI, scope list/string), default helpers still use comfyIOS, andoauthCallbackSchemeis unchanged.swift build+swift testgreen (180 tests, 0 failures, incl.ImportBoundaryTests). No new imports —OAuthClientConfigis Foundation-only, and the allowlist boundary test passes.Judgment calls (please sanity-check)
extractCodemirrorsparseCallback's control flow exactly (same guards, fail-closed), but the SDK only gained two error cases, so the app's singlemissingCallbackParametersbucket (missing/emptycode, or missingstate) maps to.authCancelledhere, whilestatemismatch maps to.authStateMismatch(as the ticket specifies). Missing-statetherefore surfaces as.authCancelled, not.authStateMismatch— deliberate: a code we can't state-verify is never redeemed.buildAuthorizationRequest(config: = .comfyIOS)is one method; the old no-arg form is just the default. Source-compatible for an SPM (source) package.OAuthTokenRefreshExecutorstill uses the comfy-ios client id (now sourced fromOAuthClientConfig.comfyIOSfor a single home) — parameterizing the refresh flow is out of scope; behavior is byte-identical.🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.