diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml
index 96c11b1d6..e3eb1e87a 100644
--- a/.github/workflows/tests.yaml
+++ b/.github/workflows/tests.yaml
@@ -29,7 +29,10 @@ env:
 jobs:
   SwiftBuild:
     name: Swift Unit Tests
-    runs-on: macos-latest-large
+    strategy:
+      matrix:
+        os: [macos-latest-large, ubuntu-latest]
+    runs-on: ${{ matrix.os }}
     timeout-minutes: 10
     steps:
     - name: Get swift version
diff --git a/Package.swift b/Package.swift
index d5b63081f..48fc333ce 100644
--- a/Package.swift
+++ b/Package.swift
@@ -11,7 +11,7 @@ var package = Package(
         .tvOS(.v12),
         .watchOS(.v7),
         .visionOS(.v1),
-        .macOS(.v10_13),
+        .macOS(.v10_15),
         .macCatalyst(.v13)
     ],
     products: [
diff --git a/README.md b/README.md
index 9203bf360..8a0be51c1 100644
--- a/README.md
+++ b/README.md
@@ -389,7 +389,7 @@ Only the last 4 major platform versions are officially supported, unless there a
 | watchOS     | 7.0       | 7.0         |
 | visionOS    | 1.0       | 1.0         |
 | macCatalyst | 13.0      | 13.0        |
-| macOS       | 12.0      | 10.13       |
+| macOS       | 12.0      | 10.15       |
 
 Once a platform version becomes unsupported, dropping support for it will not be considered a breaking change and will be done in a minor release. For example, iOS 13 will cease to be supported when iOS 18 gets released, and might be dropped in a minor release.
 
diff --git a/Sources/AuthFoundation/Network/Internal/String+AuthFoundation.swift b/Sources/AuthFoundation/Network/Internal/String+AuthFoundation.swift
index e9bcb9a69..c951d0bfc 100644
--- a/Sources/AuthFoundation/Network/Internal/String+AuthFoundation.swift
+++ b/Sources/AuthFoundation/Network/Internal/String+AuthFoundation.swift
@@ -77,7 +77,7 @@ public final class SDKVersion: Sendable {
     /// The calculated user agent string that will be included in outgoing network requests.
     public private(set) static var userAgent: String = ""
 
-    private static let lock = UnfairLock()
+    private static let lock = Lock()
     fileprivate static var sdkVersions: [SDKVersion] = []
     
     /// Register a new SDK library component to be added to the ``userAgent`` value.
diff --git a/Sources/AuthFoundation/OAuth2/Configuration.swift b/Sources/AuthFoundation/OAuth2/Configuration.swift
index b43a4ee9a..28b82ada1 100644
--- a/Sources/AuthFoundation/OAuth2/Configuration.swift
+++ b/Sources/AuthFoundation/OAuth2/Configuration.swift
@@ -49,11 +49,11 @@ extension OAuth2Client {
             
             // Ensure the base URL contains a trailing slash in its path, so request paths can be safely appended.
             if !relativeURL.lastPathComponent.isEmpty {
-                relativeURL.appendPathComponent("")
+                relativeURL = relativeURL.appendingComponent("")
             }
             
             self.baseURL = baseURL
-            self.discoveryURL = discoveryURL ?? relativeURL.appendingPathComponent(".well-known/openid-configuration")
+            self.discoveryURL = discoveryURL ?? relativeURL.appendingComponent(".well-known/openid-configuration")
             self.clientId = clientId
             self.scopes = scopes
             self.authentication = authentication
diff --git a/Sources/AuthFoundation/OAuth2/OAuth2Client.swift b/Sources/AuthFoundation/OAuth2/OAuth2Client.swift
index 723ec946a..abb910dd1 100644
--- a/Sources/AuthFoundation/OAuth2/OAuth2Client.swift
+++ b/Sources/AuthFoundation/OAuth2/OAuth2Client.swift
@@ -543,14 +543,14 @@ public final class OAuth2Client {
     // MARK: Private properties / methods
     private let delegates = DelegateCollection<OAuth2ClientDelegate>()
 
-    private let refreshLock = UnfairLock()
+    private let refreshLock = Lock()
     private(set) lazy var refreshQueue: DispatchQueue = {
         DispatchQueue(label: "com.okta.refreshQueue.\(baseURL.host ?? "unknown")",
                       qos: .userInitiated,
                       attributes: .concurrent)
     }()
 
-    private let configurationLock = UnfairLock()
+    private let configurationLock = Lock()
     private lazy var configurationQueue: DispatchQueue = {
         DispatchQueue(label: "com.okta.configurationQueue.\(baseURL.host ?? "unknown")",
                       qos: .userInitiated,
diff --git a/Sources/AuthFoundation/Token Management/Internal/UserDefaultsTokenStorage.swift b/Sources/AuthFoundation/Token Management/Internal/UserDefaultsTokenStorage.swift
index a8465215a..6bb46c391 100644
--- a/Sources/AuthFoundation/Token Management/Internal/UserDefaultsTokenStorage.swift	
+++ b/Sources/AuthFoundation/Token Management/Internal/UserDefaultsTokenStorage.swift	
@@ -12,7 +12,6 @@
 
 import Foundation
 
-#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(visionOS)
 #if canImport(LocalAuthentication) && !os(tvOS)
 import LocalAuthentication
 #else
@@ -161,4 +160,3 @@ final class UserDefaultsTokenStorage: TokenStorage {
         userDefaults.synchronize()
     }
 }
-#endif
diff --git a/Sources/AuthFoundation/User Management/Credential.swift b/Sources/AuthFoundation/User Management/Credential.swift
index 05aa18466..1e8348617 100644
--- a/Sources/AuthFoundation/User Management/Credential.swift	
+++ b/Sources/AuthFoundation/User Management/Credential.swift	
@@ -357,7 +357,7 @@ public final class Credential: Equatable, OAuth2ClientDelegate {
         }
 
         tokenObserver = NotificationCenter.default.addObserver(forName: .tokenRefreshFailed,
-                                                               object: token,
+                                                               object: nil,
                                                                queue: nil) { [weak self] notification in
             guard let self = self,
                   token == self.token
diff --git a/Sources/AuthFoundation/User Management/Internal/CredentialCoordinatorImpl.swift b/Sources/AuthFoundation/User Management/Internal/CredentialCoordinatorImpl.swift
index b5d2c0ead..2b0fbe521 100644
--- a/Sources/AuthFoundation/User Management/Internal/CredentialCoordinatorImpl.swift	
+++ b/Sources/AuthFoundation/User Management/Internal/CredentialCoordinatorImpl.swift	
@@ -94,11 +94,11 @@ final class CredentialCoordinatorImpl: CredentialCoordinator {
     }
     
     static func defaultTokenStorage() -> TokenStorage {
-        #if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(visionOS)
-        KeychainTokenStorage()
-        #else
+         #if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(visionOS)
+         KeychainTokenStorage()
+         #else
         UserDefaultsTokenStorage()
-        #endif
+         #endif
     }
     
     static func defaultCredentialDataSource() -> CredentialDataSource {
diff --git a/Sources/AuthFoundation/Utilities/JSONValue.swift b/Sources/AuthFoundation/Utilities/JSONValue.swift
index 173a45db5..74f1ef741 100644
--- a/Sources/AuthFoundation/Utilities/JSONValue.swift
+++ b/Sources/AuthFoundation/Utilities/JSONValue.swift
@@ -251,13 +251,13 @@ extension JSON: Codable {
 
 fileprivate extension NSNumber {
     var isFloatingPoint: Bool {
-        let type = CFNumberGetType(self as CFNumber)
-        switch type {
-        case .floatType, .float32Type, .float64Type, .cgFloatType, .doubleType:
+        if strcmp(objCType, "f") == 0 ||
+            strcmp(objCType, "d") == 0
+        {
             return true
-        default:
-            return false
         }
+        
+        return false
     }
 }
 
diff --git a/Sources/AuthFoundation/Utilities/Lock.swift b/Sources/AuthFoundation/Utilities/Lock.swift
new file mode 100644
index 000000000..aa277ae2a
--- /dev/null
+++ b/Sources/AuthFoundation/Utilities/Lock.swift
@@ -0,0 +1,104 @@
+//
+// Copyright (c) 2023-Present, Okta, Inc. and/or its affiliates. All rights reserved.
+// The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.")
+//
+// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//
+// See the License for the specific language governing permissions and limitations under the License.
+//
+
+import Foundation
+
+#if canImport(Darwin)
+import Darwin
+#elseif canImport(Glibc)
+import Glibc
+#elseif canImport(Musl)
+import Musl
+#elseif canImport(Bionic)
+import Bionic
+#else
+#error("Unsupported platform")
+#endif
+
+// **Note:** It would be preferable to use OSAllocatedUnfairLock for this, but this would mean dropping support for older OS versions. While this approach is safe, OSAllocatedUnfairLock provides more features we might need in the future.
+//
+// If the minimum supported version of this SDK is to increase in the future, this class should be removed and replaced with OSAllocatedUnfairLock.
+final class Lock: NSLocking {
+    #if canImport(Darwin)
+    private typealias LockType = os_unfair_lock
+    #elseif canImport(Glibc) || canImport(Musl) || canImport(Bionic)
+    private typealias LockType = pthread_mutex_t
+    #else
+    #error("Unsupported platform")
+    #endif
+
+    private let _lock: UnsafeMutablePointer<LockType> = {
+        let result = UnsafeMutablePointer<LockType>.allocate(capacity: 1)
+
+        #if canImport(Darwin)
+        result.initialize(to: os_unfair_lock())
+        #elseif canImport(Glibc) || canImport(Musl) || canImport(Bionic)
+        let status = pthread_mutex_init(result, nil)
+        precondition(status == 0, "pthread_mutex_init failed")
+        #else
+        #error("Unsupported platform")
+        #endif
+        
+        return result
+    }()
+    
+    deinit {
+        #if canImport(Glibc) || canImport(Musl) || canImport(Bionic)
+        let status = pthread_mutex_destroy(_lock)
+        precondition(status == 0, "pthread_mutex_destroy failed")
+        #endif
+        _lock.deinitialize(count: 1)
+        _lock.deallocate()
+    }
+    
+    func lock() {
+        #if canImport(Darwin)
+        os_unfair_lock_lock(_lock)
+        #elseif canImport(Glibc) || canImport(Musl) || canImport(Bionic)
+        let status = pthread_mutex_lock(_lock)
+        precondition(status == 0, "pthread_mutex_lock failed")
+        #else
+        #error("Unsupported platform")
+        #endif
+    }
+
+    func tryLock() -> Bool {
+        #if canImport(Darwin)
+        return os_unfair_lock_trylock(_lock)
+        #elseif canImport(Glibc) || canImport(Musl) || canImport(Bionic)
+        return pthread_mutex_trylock(_lock) == 0
+        #else
+        #error("Unsupported platform")
+        #endif
+    }
+
+    func unlock() {
+        #if canImport(Darwin)
+        os_unfair_lock_unlock(_lock)
+        #elseif canImport(Glibc) || canImport(Musl) || canImport(Bionic)
+        let status = pthread_mutex_unlock(_lock)
+        precondition(status == 0, "pthread_mutex_unlock failed")
+        #else
+        #error("Unsupported platform")
+        #endif
+    }
+
+    #if !canImport(Darwin)
+    func withLock<T>(_ body: () throws -> T) rethrows -> T {
+        self.lock()
+        defer {
+            self.unlock()
+        }
+        return try body()
+    }
+    #endif
+}
\ No newline at end of file
diff --git a/Sources/AuthFoundation/Utilities/TimeCoordinator.swift b/Sources/AuthFoundation/Utilities/TimeCoordinator.swift
index 3cbcdc51b..c7090a5c6 100644
--- a/Sources/AuthFoundation/Utilities/TimeCoordinator.swift
+++ b/Sources/AuthFoundation/Utilities/TimeCoordinator.swift
@@ -12,6 +12,10 @@
 
 import Foundation
 
+#if os(Linux)
+import FoundationNetworking
+#endif
+
 /// Protocol used to return dates and times coordinated against trusted sources.
 ///
 /// This can be used to customize the behavior of how dates and times are calculated, when used on devices that may have skewed or incorrect clocks.
@@ -53,7 +57,7 @@ class DefaultTimeCoordinator: TimeCoordinator, OAuth2ClientDelegate {
         Date.coordinator = DefaultTimeCoordinator()
     }
     
-    private let lock = UnfairLock()
+    private let lock = Lock()
     private var _offset: TimeInterval
     private(set) var offset: TimeInterval {
         get { lock.withLock { _offset } }
diff --git a/Sources/AuthFoundation/Utilities/URL+InternalExtensions.swift b/Sources/AuthFoundation/Utilities/URL+InternalExtensions.swift
new file mode 100644
index 000000000..37c5510d8
--- /dev/null
+++ b/Sources/AuthFoundation/Utilities/URL+InternalExtensions.swift
@@ -0,0 +1,33 @@
+//
+// Copyright (c) 2024-Present, Okta, Inc. and/or its affiliates. All rights reserved.
+// The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.")
+//
+// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//
+// See the License for the specific language governing permissions and limitations under the License.
+//
+
+import Foundation
+
+extension URL {
+    @inlinable
+    // Workaround to address a known bug with URL.appendingPathComponent on Linux.
+    // https://github.com/apple/swift-corelibs-foundation/issues/4849
+    func appendingComponent(_ component: String) -> URL {
+        #if os(Linux)
+        var components = URLComponents(url: self, resolvingAgainstBaseURL: true)!
+        if !components.path.hasSuffix("/") {
+            components.path.append("/")
+        }
+        components.path.append(component)
+        return components.url!
+        #else
+        var result = self
+        result.appendPathComponent(component)
+        return result
+        #endif
+    }
+}
diff --git a/Sources/AuthFoundation/Utilities/UnsafeLock.swift b/Sources/AuthFoundation/Utilities/UnsafeLock.swift
deleted file mode 100644
index f6c09b52b..000000000
--- a/Sources/AuthFoundation/Utilities/UnsafeLock.swift
+++ /dev/null
@@ -1,41 +0,0 @@
-//
-// Copyright (c) 2023-Present, Okta, Inc. and/or its affiliates. All rights reserved.
-// The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.")
-//
-// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-//
-// See the License for the specific language governing permissions and limitations under the License.
-//
-
-import Foundation
-
-// **Note:** It would be preferable to use OSAllocatedUnfairLock for this, but this would mean dropping support for older OS versions. While this approach is safe, OSAllocatedUnfairLock provides more features we might need in the future.
-//
-// If the minimum supported version of this SDK is to increase in the future, this class should be removed and replaced with OSAllocatedUnfairLock.
-final class UnfairLock: NSLocking {
-    private let _lock: UnsafeMutablePointer<os_unfair_lock> = {
-        let result = UnsafeMutablePointer<os_unfair_lock>.allocate(capacity: 1)
-        result.initialize(to: os_unfair_lock())
-        return result
-    }()
-    
-    deinit {
-        _lock.deinitialize(count: 1)
-        _lock.deallocate()
-    }
-    
-    func lock() {
-        os_unfair_lock_lock(_lock)
-    }
-
-    func tryLock() -> Bool {
-        os_unfair_lock_trylock(_lock)
-    }
-
-    func unlock() {
-        os_unfair_lock_unlock(_lock)
-    }
-}
diff --git a/Sources/OktaOAuth2/Authentication/SessionTokenFlow.swift b/Sources/OktaOAuth2/Authentication/SessionTokenFlow.swift
index 6dd7297bd..4edab0680 100644
--- a/Sources/OktaOAuth2/Authentication/SessionTokenFlow.swift
+++ b/Sources/OktaOAuth2/Authentication/SessionTokenFlow.swift
@@ -13,6 +13,10 @@
 import Foundation
 import AuthFoundation
 
+#if os(Linux)
+import FoundationNetworking
+#endif
+
 /// An authentication flow class that exchanges a Session Token for access tokens.
 ///
 /// This flow is typically used in conjunction with the [classic Okta native authentication library](https://github.com/okta/okta-auth-swift). For native authentication using the Okta Identity Engine (OIE), please use the [Okta IDX library](https://github.com/okta/okta-idx-swift).
diff --git a/Sources/WebAuthenticationUI/Extensions/WebAuthentication+Deprecated.swift b/Sources/WebAuthenticationUI/Extensions/WebAuthentication+Deprecated.swift
index 88c8053ce..0abdba03b 100644
--- a/Sources/WebAuthenticationUI/Extensions/WebAuthentication+Deprecated.swift
+++ b/Sources/WebAuthenticationUI/Extensions/WebAuthentication+Deprecated.swift
@@ -13,6 +13,7 @@
 import Foundation
 
 // TODO: Remove on the next major release.
+#if canImport(UIKit) || canImport(AppKit)
 extension WebAuthentication {
     @available(*, deprecated, renamed: "signIn(from:options:completion:)")
     public final func signIn(from window: WindowAnchor?,
@@ -127,3 +128,4 @@ extension WebAuthentication {
         try await signOut(from: window, token: token, options: options(from: additionalParameters))
     }
 }
+#endif
\ No newline at end of file
diff --git a/Sources/WebAuthenticationUI/Internal/Bundle+WebAuthenticationUI.swift b/Sources/WebAuthenticationUI/Internal/Bundle+WebAuthenticationUI.swift
index 264092c74..105dba361 100644
--- a/Sources/WebAuthenticationUI/Internal/Bundle+WebAuthenticationUI.swift
+++ b/Sources/WebAuthenticationUI/Internal/Bundle+WebAuthenticationUI.swift
@@ -12,6 +12,7 @@
 
 import Foundation
 
+#if canImport(UIKit) || canImport(AppKit)
 #if !SWIFT_PACKAGE
 private let sharedLocalizationBundle: Bundle = {
     Bundle(for: WebAuthentication.self)
@@ -27,3 +28,4 @@ extension Bundle {
         #endif
     }
 }
+#endif
\ No newline at end of file
diff --git a/Sources/WebAuthenticationUI/Internal/Options+Extensions.swift b/Sources/WebAuthenticationUI/Internal/Options+Extensions.swift
index 709a9ee4d..630db255e 100644
--- a/Sources/WebAuthenticationUI/Internal/Options+Extensions.swift
+++ b/Sources/WebAuthenticationUI/Internal/Options+Extensions.swift
@@ -13,6 +13,7 @@
 import Foundation
 import OktaOAuth2
 
+#if canImport(UIKit) || canImport(AppKit)
 extension WebAuthentication.Option {
     var queryItems: [String: String] {
         switch self {
@@ -81,3 +82,4 @@ extension Collection where Element == WebAuthentication.Option {
         return .init(state: state, maxAge: maxAge)
     }
 }
+#endif
\ No newline at end of file
diff --git a/Sources/WebAuthenticationUI/Version.swift b/Sources/WebAuthenticationUI/Version.swift
index c0dd288d5..115e12158 100644
--- a/Sources/WebAuthenticationUI/Version.swift
+++ b/Sources/WebAuthenticationUI/Version.swift
@@ -13,7 +13,9 @@
 import Foundation
 import AuthFoundation
 
+#if canImport(UIKit) || canImport(AppKit)
 // swiftlint:disable identifier_name
 @_documentation(visibility: private)
 public let Version = SDKVersion(sdk: "okta-webauthenticationui-swift", version: "1.8.2")
 // swiftlint:enable identifier_name
+#endif
\ No newline at end of file
diff --git a/Tests/AuthFoundationTests/APIClientTests.swift b/Tests/AuthFoundationTests/APIClientTests.swift
index bb3491a8f..ea423f6e4 100644
--- a/Tests/AuthFoundationTests/APIClientTests.swift
+++ b/Tests/AuthFoundationTests/APIClientTests.swift
@@ -14,6 +14,10 @@ import XCTest
 @testable import AuthFoundation
 @testable import TestCommon
 
+#if os(Linux)
+import FoundationNetworking
+#endif
+
 struct MockApiParsingContext: APIParsingContext {
     var codingUserInfo: [CodingUserInfoKey : Any]?
     
diff --git a/Tests/AuthFoundationTests/APIRetryTests.swift b/Tests/AuthFoundationTests/APIRetryTests.swift
index 8a9162021..688454d5a 100644
--- a/Tests/AuthFoundationTests/APIRetryTests.swift
+++ b/Tests/AuthFoundationTests/APIRetryTests.swift
@@ -14,6 +14,10 @@ import XCTest
 @testable import AuthFoundation
 @testable import TestCommon
 
+#if os(Linux)
+import FoundationNetworking
+#endif
+
 class APIRetryDelegateRecorder: APIClientDelegate {
     var response: APIRetry?
     private(set) var requests: [URLRequest] = []
diff --git a/Tests/AuthFoundationTests/DefaultTimeCoordinatorTests.swift b/Tests/AuthFoundationTests/DefaultTimeCoordinatorTests.swift
index 518ee7e65..c043e4ca9 100644
--- a/Tests/AuthFoundationTests/DefaultTimeCoordinatorTests.swift
+++ b/Tests/AuthFoundationTests/DefaultTimeCoordinatorTests.swift
@@ -14,6 +14,10 @@ import XCTest
 @testable import AuthFoundation
 @testable import TestCommon
 
+#if os(Linux)
+import FoundationNetworking
+#endif
+
 final class DefaultTimeCoordinatorTests: XCTestCase {
     var coordinator: DefaultTimeCoordinator!
     var client: MockApiClient!
diff --git a/Tests/AuthFoundationTests/OAuth2ClientTests.swift b/Tests/AuthFoundationTests/OAuth2ClientTests.swift
index 397e2f27b..e19c038d1 100644
--- a/Tests/AuthFoundationTests/OAuth2ClientTests.swift
+++ b/Tests/AuthFoundationTests/OAuth2ClientTests.swift
@@ -2,6 +2,10 @@ import XCTest
 @testable import TestCommon
 @testable import AuthFoundation
 
+#if os(Linux)
+import FoundationNetworking
+#endif
+
 final class OAuth2ClientTests: XCTestCase {
     let issuer = URL(string: "https://example.com")!
     let redirectUri = URL(string: "com.example:/callback")!
diff --git a/Tests/OktaDirectAuthTests/ErrorTests.swift b/Tests/OktaDirectAuthTests/ErrorTests.swift
index c848b9174..873bb701c 100644
--- a/Tests/OktaDirectAuthTests/ErrorTests.swift
+++ b/Tests/OktaDirectAuthTests/ErrorTests.swift
@@ -50,18 +50,10 @@ final class ErrorTests: XCTestCase {
         XCTAssertEqual(DirectAuthenticationFlowError(OAuth2Error.network(error: .invalidRequestData)),
                        .network(error: .invalidRequestData))
 
-        // Ensure a generic error embedded in OAuth2Error becomes the appropriate error type
-        XCTAssertEqual(DirectAuthenticationFlowError(OAuth2Error.error(KeychainError.invalidFormat)),
-                       .other(error: KeychainError.invalidFormat))
-
         // Ensure a APIClientError becomes the appropriate type
         XCTAssertEqual(DirectAuthenticationFlowError(APIClientError.invalidRequestData),
                        .network(error: .invalidRequestData))
 
-        // Ensure a generic error in APIClientError becomes the appropriate type
-        XCTAssertEqual(DirectAuthenticationFlowError(APIClientError.serverError(KeychainError.invalidFormat)),
-                       .other(error: KeychainError.invalidFormat))
-
         // Ensure an OAUth2ServerError becomes a .server(error:)
         let serverError = try defaultJSONDecoder.decode(OAuth2ServerError.self, from: """
             {
@@ -71,5 +63,15 @@ final class ErrorTests: XCTestCase {
             """.data(using: .utf8)!)
         XCTAssertEqual(DirectAuthenticationFlowError(APIClientError.serverError(serverError)),
                        .server(error: serverError))
+
+        #if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(visionOS)
+        // Ensure a generic error embedded in OAuth2Error becomes the appropriate error type
+        XCTAssertEqual(DirectAuthenticationFlowError(OAuth2Error.error(KeychainError.invalidFormat)),
+                       .other(error: KeychainError.invalidFormat))
+
+        // Ensure a generic error in APIClientError becomes the appropriate type
+        XCTAssertEqual(DirectAuthenticationFlowError(APIClientError.serverError(KeychainError.invalidFormat)),
+                       .other(error: KeychainError.invalidFormat))
+        #endif
     }
 }
diff --git a/Tests/TestCommon/MockApiClient.swift b/Tests/TestCommon/MockApiClient.swift
index de1f68af7..c0680ece5 100644
--- a/Tests/TestCommon/MockApiClient.swift
+++ b/Tests/TestCommon/MockApiClient.swift
@@ -13,6 +13,10 @@
 import Foundation
 @testable import AuthFoundation
 
+#if os(Linux)
+import FoundationNetworking
+#endif
+
 class MockApiClient: APIClient {
     var baseURL: URL
     var session: URLSessionProtocol
diff --git a/Tests/TestCommon/MockApiRequest.swift b/Tests/TestCommon/MockApiRequest.swift
index 5b5fcc07a..c496dcc34 100644
--- a/Tests/TestCommon/MockApiRequest.swift
+++ b/Tests/TestCommon/MockApiRequest.swift
@@ -13,6 +13,10 @@
 import Foundation
 @testable import AuthFoundation
 
+#if os(Linux)
+import FoundationNetworking
+#endif
+
 struct MockApiRequest: APIRequest {
     var url: URL
     var cachePolicy: URLRequest.CachePolicy
diff --git a/Tests/TestCommon/URLRequest+Extensions.swift b/Tests/TestCommon/URLRequest+Extensions.swift
index fd32511e0..f7c99d3b7 100644
--- a/Tests/TestCommon/URLRequest+Extensions.swift
+++ b/Tests/TestCommon/URLRequest+Extensions.swift
@@ -12,6 +12,10 @@
 
 import Foundation
 
+#if os(Linux)
+import FoundationNetworking
+#endif
+
 extension URLRequest {
     var bodyString: String? {
         guard let body = httpBody else { return nil }
diff --git a/Tests/TestCommon/XCTestCase+Extensions.swift b/Tests/TestCommon/XCTestCase+Extensions.swift
index 463731b25..d89732773 100644
--- a/Tests/TestCommon/XCTestCase+Extensions.swift
+++ b/Tests/TestCommon/XCTestCase+Extensions.swift
@@ -85,8 +85,8 @@ public extension XCTestCase {
         let group = DispatchGroup()
         for queue in queues {
             for _ in 0..<iterationCount {
+                group.enter()
                 queue.async {
-                    group.enter()
                     Task {
                         try await block()
                         group.leave()