Skip to content

Commit

Permalink
fix(auth): store code verifier in keychain (#502)
Browse files Browse the repository at this point in the history
  • Loading branch information
grdsdev committed Aug 14, 2024
1 parent 83f3385 commit b86154a
Show file tree
Hide file tree
Showing 10 changed files with 50 additions and 10 deletions.
1 change: 1 addition & 0 deletions Sources/Auth/AuthClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ public final class AuthClient: Sendable {
configuration: configuration,
http: HTTPClient(configuration: configuration),
api: APIClient(clientID: clientID),
codeVerifierStorage: .live(clientID: clientID),
sessionStorage: .live(clientID: clientID),
sessionManager: .live(clientID: clientID)
)
Expand Down
2 changes: 0 additions & 2 deletions Sources/Auth/Defaults.swift
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,4 @@ extension AuthClient.Configuration {

/// The default value when initializing a ``AuthClient`` instance.
public static let defaultAutoRefreshToken: Bool = true

static let defaultStorageKey = "supabase.auth.token"
}
32 changes: 28 additions & 4 deletions Sources/Auth/Internal/CodeVerifierStorage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,36 @@ struct CodeVerifierStorage: Sendable {
}

extension CodeVerifierStorage {
static var live: Self {
let code = LockIsolated(String?.none)
static func live(clientID: AuthClientID) -> Self {
var configuration: AuthClient.Configuration { Dependencies[clientID].configuration }
var key: String { "\(configuration.storageKey ?? STORAGE_KEY)-code-verifier" }

return Self(
get: { code.value },
set: { code.setValue($0) }
get: {
do {
guard let data = try configuration.localStorage.retrieve(key: key) else {
configuration.logger?.debug("Code verifier not found.")
return nil
}
return String(decoding: data, as: UTF8.self)
} catch {
configuration.logger?.error("Failure loading code verifier: \(error.localizedDescription)")
return nil
}
},
set: { code in
do {
if let code, let data = code.data(using: .utf8) {
try configuration.localStorage.store(key: key, value: data)
} else if code == nil {
try configuration.localStorage.remove(key: key)
} else {
configuration.logger?.error("Code verifier is not a valid UTF8 string.")
}
} catch {
configuration.logger?.error("Failure storing code verifier: \(error.localizedDescription)")
}
}
)
}
}
1 change: 1 addition & 0 deletions Sources/Auth/Internal/Contants.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@
import Foundation

let EXPIRY_MARGIN: TimeInterval = 30
let STORAGE_KEY = "supabase.auth.token"
3 changes: 2 additions & 1 deletion Sources/Auth/Internal/Dependencies.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@ struct Dependencies: Sendable {
var configuration: AuthClient.Configuration
var http: any HTTPClientType
var api: APIClient
var codeVerifierStorage: CodeVerifierStorage
var sessionStorage: SessionStorage
var sessionManager: SessionManager

var eventEmitter = AuthStateChangeEventEmitter()
var date: @Sendable () -> Date = { Date() }
var codeVerifierStorage = CodeVerifierStorage.live

var urlOpener: URLOpener = .live

var encoder: JSONEncoder { configuration.encoder }
Expand Down
2 changes: 1 addition & 1 deletion Sources/Auth/Internal/SessionStorage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ struct SessionStorage {
extension SessionStorage {
static func live(clientID: AuthClientID) -> SessionStorage {
var key: String {
Dependencies[clientID].configuration.storageKey ?? AuthClient.Configuration.defaultStorageKey
Dependencies[clientID].configuration.storageKey ?? STORAGE_KEY
}

var oldKey: String { "supabase.session" }
Expand Down
4 changes: 2 additions & 2 deletions Supabase.xcworkspace/xcshareddata/swiftpm/Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/pointfreeco/swift-snapshot-testing",
"state" : {
"revision" : "c097f955b4e724690f0fc8ffb7a6d4b881c9c4e3",
"version" : "1.17.2"
"revision" : "6d932a79e7173b275b96c600c86c603cf84f153c",
"version" : "1.17.4"
}
},
{
Expand Down
13 changes: 13 additions & 0 deletions Tests/AuthTests/MockHelpers.swift
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import ConcurrencyExtras
import Foundation
import TestHelpers

Expand All @@ -23,7 +24,19 @@ extension Dependencies {
),
http: HTTPClientMock(),
api: APIClient(clientID: AuthClientID()),
codeVerifierStorage: CodeVerifierStorage.mock,
sessionStorage: SessionStorage.live(clientID: AuthClientID()),
sessionManager: SessionManager.live(clientID: AuthClientID())
)
}

extension CodeVerifierStorage {
static var mock: CodeVerifierStorage {
let code = LockIsolated<String?>(nil)

return Self(
get: { code.value },
set: { code.setValue($0) }
)
}
}
1 change: 1 addition & 0 deletions Tests/AuthTests/SessionManagerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ final class SessionManagerTests: XCTestCase {
),
http: http,
api: APIClient(clientID: clientID),
codeVerifierStorage: .mock,
sessionStorage: SessionStorage.live(clientID: clientID),
sessionManager: SessionManager.live(clientID: clientID)
)
Expand Down
1 change: 1 addition & 0 deletions Tests/AuthTests/StoredSessionTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ final class StoredSessionTests: XCTestCase {
),
http: HTTPClientMock(),
api: .init(clientID: clientID),
codeVerifierStorage: .mock,
sessionStorage: .live(clientID: clientID),
sessionManager: .live(clientID: clientID)
)
Expand Down

0 comments on commit b86154a

Please sign in to comment.