supabase / supabase-swift

A Swift client for Supabase
https://supabase.com/docs/reference/swift
MIT License
680 stars 100 forks source link

`Auth.KeychainError(code=itemNotFound)` on MacOS with SDK v2.16 #516

Open rebryk opened 2 weeks ago

rebryk commented 2 weeks ago

Bug report

Describe the bug

When i switched from supabase v2.0 to v2.16 try await supabaseClient.auth.session throws Auth.KeychainError(code=itemNotFound) on MacOS.

To Reproduce

  1. Create a sign URL

    try supabaseClient.auth.getOAuthSignInURL(
      provider: Provider.google,
      redirectTo: `app-schema://auth`
    )
  2. Open url

    NSWorkspace.shared.open(url)
  3. Handle deeplink after Google authorization

    func application(_ application: NSApplication, open urls: [URL]) {
    if let url = urls.first, url.host == "auth" {
        Task {
            try await supabaseClient.auth.session(from: url)
        }
    }
    }
  4. Step 3 returns a valid session; however, try await supabaseClient.auth.session will throw an Auth.KeychainError(code=itemNotFound) error.

Expected behavior

I expect try await supabaseClient.auth.session to restore the session from the keychain as it did before in previous SDK versions.

System information

grdsdev commented 2 weeks ago

Hi @rebryk try attaching a logger on Supabase initialization, and let me know if you see any other log being fired, this is how you can do it.

let supabase = SupabaseClient(
  supabaseURL: URL(string: "URL")!,
  supabaseKey: "API_KEY",
  options: .init(
    global: .init(logger: AppLogger())
  )
)

struct AppLogger: SupabaseLogger {
  let logger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "supabase")

  func log(message: SupabaseLogMessage) {
    switch message.level {
    case .verbose:
      logger.log(level: .info, "\(message.description)")
    case .debug:
      logger.log(level: .debug, "\(message.description)")
    case .warning, .error:
      logger.log(level: .error, "\(message.description)")
    }
  }
}
rebryk commented 2 weeks ago

@grdsdev

2024-08-28T08:55:35-0700 info supabase : [n/a] 2024-08-28T15:55:35Z [verbose] [Helpers] [Helpers/LoggerInterceptor.intercept(_:next:):23] Request: POST https://<URL>/auth/v1/token
2024-08-28T08:55:35-0700 info supabase : [n/a] 2024-08-28T15:55:35Z [verbose] [Helpers] [Helpers/LoggerInterceptor.intercept(_:next:):33] Response: Status code: 200 Content-Length: 3413
2024-08-28T08:55:35-0700 error supabase : [n/a] 2024-08-28T15:55:35Z [error] [Auth] [Auth/SessionManager.update(_:):103] Failed to store session: Unspecified Keychain error: -34018.
2024-08-28T08:55:35-0700 debug supabase : [n/a] 2024-08-28T15:55:35Z [debug] [Auth] [Auth/SessionManager.session():41] begin
2024-08-28T08:55:35-0700 debug supabase : [n/a] 2024-08-28T15:55:35Z [debug] [Auth] [Auth/SessionManager.session():41] error: errSecItemNotFound: The item cannot be found.
2024-08-28T08:55:35-0700 debug supabase : [n/a] 2024-08-28T15:55:35Z [debug] [Auth] [Auth/SessionManager.session():41] end
grdsdev commented 2 weeks ago

The key is Failed to store session: Unspecified Keychain error: -34018. That error is errSecMissingEntitlement, it means there is something wrong with the added entitlement, can you check this https://developer.apple.com/documentation/security/errsecmissingentitlement and verify if your project is correctly configured?

I'll also check on my side, if there is anything wrong, since you mentioned it stoped working.

rebryk commented 2 weeks ago

As far as I understand, macOS apps have default access to a private Keychain for storing app-specific data (you do not need to add any entitlements, i don't use keychain sharing). Also, everything works with previous versions of the SDK.

@grdsdev so it is most likely an issue with the new version

Let me know if i can help

grdsdev commented 2 weeks ago

It seems it started after this https://github.com/supabase/supabase-swift/pull/455

rebryk commented 2 weeks ago

you are right: 2.14 works, and 2.14.1 does not

grdsdev commented 2 weeks ago

Doing a few tests and if you add the keychain sharing capability to your app, even if you don't assign any access group, it works, will try to find on docs why that happens.

rebryk commented 2 weeks ago

Yeah, when I add the keychain sharing capability, the app works. Hopefully it will not break anythings else

rebryk commented 2 weeks ago

I have an issue when I run a signed release with empty keychain sharing capability: app.getfluently.Fluently: Unsatisfied entitlements: keychain-access-groups

rebryk commented 2 weeks ago

Same thing when I add:

<key>keychain-access-groups</key>
<array>
    <string>$(AppIdentifierPrefix)app.getfluently.Fluently</string>
</array>
grdsdev commented 2 weeks ago

@rebryk if you add an access group, then you need to provide a custom KeychainLocalStorage implementation with the access group.

rebryk commented 2 weeks ago

@grdsdev do you have an off-the-shelf implementation? i just want to use supabase in a way I used it before

grdsdev commented 1 week ago

You can use the following code, once I merge this https://github.com/supabase/supabase-swift/pull/519

KeychainLocalStorage is the default implementation used internally, and it is exposed so you can customize it.

let supabase = SupabaseClient(
  supabaseURL: URL(string: "https://project-id.supabase.com")!,
  supabaseKey: "supabase-anon-key",
  options: .init(
    auth: .init(
      localStorage: KeychainLocalStorage(
        accessGroup: "<# Your Team ID #>.app.getfluently.Fluently"
      )
    )
  )
)
rebryk commented 1 week ago

@grdsdev i have an issue with keychain-access-groups capability, so i would probably stick to v2.14.0

  1. I add capability

    <key>keychain-access-groups</key>
    <array>
        <string>$(AppIdentifierPrefix)app.getfluently.Fluently</string>
    </array>
  2. Sign the build

    codesign \
    --force \
    --deep \
    --entitlements "$ENTITLEMENTS_FILE" \
    --options runtime \
    --sign $devTeamID \
    "Builds/$BUILD_TYPE/root/${APP_NAME}.app"
  3. Get an error when open the signed app app.getfluently.Fluently: Unsatisfied entitlements: keychain-access-groups