`Auth.KeychainError(code=itemNotFound)` on MacOS with SDK v2.16
Bug report
- [+] I confirm this is a bug with Supabase, not with my own application.
- [+] I confirm I have searched the Docs, GitHub Discussions, and Discord.
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
- Create a sign URL
try supabaseClient.auth.getOAuthSignInURL(
provider: Provider.google,
redirectTo: `app-schema://auth`
)
- Open url
NSWorkspace.shared.open(url)
- 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)
}
}
}
- Step 3 returns a valid session; however,
try await supabaseClient.auth.sessionwill throw anAuth.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
- OS: macOS
- Browser (if applies) Arc Browser
- Version of supabase: v2.16
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)")
}
}
}
@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
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.
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
It seems it started after this https://github.com/supabase/supabase-swift/pull/455
you are right: 2.14 works, and 2.14.1 does not
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.
Yeah, when I add the keychain sharing capability, the app works. Hopefully it will not break anythings else
I have an issue when I run a signed release with empty keychain sharing capability:
app.getfluently.Fluently: Unsatisfied entitlements: keychain-access-groups
Same thing when I add:
<key>keychain-access-groups</key>
<array>
<string>$(AppIdentifierPrefix)app.getfluently.Fluently</string>
</array>
@rebryk if you add an access group, then you need to provide a custom KeychainLocalStorage implementation with the access group.
@grdsdev do you have an off-the-shelf implementation? i just want to use supabase in a way I used it before
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"
)
)
)
)
@grdsdev i have an issue with keychain-access-groups capability, so i would probably stick to v2.14.0
- I add capability
<key>keychain-access-groups</key>
<array>
<string>$(AppIdentifierPrefix)app.getfluently.Fluently</string>
</array>
- Sign the build
codesign \
--force \
--deep \
--entitlements "$ENTITLEMENTS_FILE" \
--options runtime \
--sign $devTeamID \
"Builds/$BUILD_TYPE/root/${APP_NAME}.app"
- Get an error when open the signed app
app.getfluently.Fluently: Unsatisfied entitlements: keychain-access-groups
@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
I have the same issue ! But it happens when i try to sing in with Apple, and thats my code:
var supabase = SupabaseClient(
supabaseURL: URL(string:AppConstants.supabaseURLString)!,
supabaseKey: AppConstants.supabaseKey,
options: SupabaseClientOptions(
auth: .init(storage: KeychainLocalStorage(
service: "<# service #>",
accessGroup: "<# teamid.com.app.identifier #>"
)
),
global: SupabaseClientOptions.GlobalOptions(
headers: [
"rs-user-id": UserStore.shared.userId ?? ""
],
logger: Logger()
)
)
)
Task {
do {
guard let credential = authorization.credential as? ASAuthorizationAppleIDCredential else {
return
}
guard let idToken = credential.identityToken
.flatMap({ String(data: $0, encoding: .utf8) }) else {
return
}
try await RemoteClient.shared.supabase.auth.signInWithIdToken(
credentials: .init(
provider: .apple,
idToken: idToken
)
)
print("Apple login success!")
} catch {
dump(error)
}
}
Can you help me, thanks! @grdsdev