diff --git a/Sources/JWT/JWTSigner.swift b/Sources/JWT/JWTSigner.swift index 722eb03..5a9e15c 100644 --- a/Sources/JWT/JWTSigner.swift +++ b/Sources/JWT/JWTSigner.swift @@ -80,11 +80,11 @@ extension JWTSigner { } /// Creates an HMAC-based `CustomJWTAlgorithm` and `JWTSigner`. - private static func hmac(_ hmac: HMAC, name: String, key: LosslessDataConvertible) -> JWTSigner { + private static func hmac(_ hmac: @autoclosure @escaping () -> HMAC, name: String, key: LosslessDataConvertible) -> JWTSigner { let alg = CustomJWTAlgorithm(name: name, sign: { plaintext in - return try hmac.authenticate(plaintext, key: key) + return try hmac().authenticate(plaintext, key: key) }, verify: { signature, plaintext in - return try hmac.authenticate(plaintext, key: key) == signature.convertToData() + return try hmac().authenticate(plaintext, key: key) == signature.convertToData() }) return .init(algorithm: alg) } diff --git a/Tests/JWTTests/JWTTests.swift b/Tests/JWTTests/JWTTests.swift index 996cb95..610b135 100644 --- a/Tests/JWTTests/JWTTests.swift +++ b/Tests/JWTTests/JWTTests.swift @@ -79,6 +79,36 @@ class JWTTests: XCTestCase { XCTAssertEqual(publicVerified.payload.name, "Foo") XCTAssertEqual(privateVerified.payload.name, "Foo") } + + func testThreadSafety() throws { + let signer = JWTSigner.hs256(key: "test") + + let start = DispatchGroup() + start.enter() + start.enter() + + let done = DispatchGroup() + done.enter() + done.enter() + + Thread.async { + start.leave() + start.wait() + for _ in 0..<100 { + _ = try? signer.verify("foo", header: "bar", payload: "baz") + } + done.leave() + } + Thread.async { + start.leave() + start.wait() + for _ in 0..<100 { + _ = try? signer.verify("foo", header: "bar", payload: "baz") + } + done.leave() + } + done.wait() + } static var allTests = [ ("testParse", testParse), @@ -87,6 +117,7 @@ class JWTTests: XCTestCase { ("testExpirationEncoding", testExpirationEncoding), ("testSigners", testSigners), ("testRSA", testRSA), + ("testThreadSafety", testThreadSafety), ] }