diff --git a/Sources/JSONWebToken/JWT+Encryption.swift b/Sources/JSONWebToken/JWT+Encryption.swift index e136c46..b6d5ac4 100644 --- a/Sources/JSONWebToken/JWT+Encryption.swift +++ b/Sources/JSONWebToken/JWT+Encryption.swift @@ -54,7 +54,7 @@ extension JWT { return JWT( payload: payload, format: .jwe(try JWE( - payload: JSONEncoder.jose.encode(payload), + payload: JSONEncoder.jwt.encode(payload), protectedHeader: protectedHeader, unprotectedHeader: unprotectedHeader, senderKey: senderKey, diff --git a/Sources/JSONWebToken/JWT+Signing.swift b/Sources/JSONWebToken/JWT+Signing.swift index 03f5fad..5170ff8 100644 --- a/Sources/JSONWebToken/JWT+Signing.swift +++ b/Sources/JSONWebToken/JWT+Signing.swift @@ -40,7 +40,7 @@ extension JWT { return JWT( payload: payload, format: .jws(try JWS( - payload: JSONEncoder.jose.encode(payload), + payload: JSONEncoder.jwt.encode(payload), protectedHeader: protectedHeader, key: key )) @@ -103,7 +103,7 @@ extension JWT { protectedHeader.contentType = "JWT" return try JWS( - payload: JSONEncoder.jose.encode(jwtString.tryToData()), + payload: JSONEncoder.jwt.encode(jwtString.tryToData()), protectedHeader: protectedHeader, key: key ) diff --git a/Sources/JSONWebToken/JWT+Verification.swift b/Sources/JSONWebToken/JWT+Verification.swift index 1eba979..9b62e1e 100644 --- a/Sources/JSONWebToken/JWT+Verification.swift +++ b/Sources/JSONWebToken/JWT+Verification.swift @@ -61,7 +61,7 @@ extension JWT { expectedAudience: expectedAudience ) } - let payload = try JSONDecoder().decode(C.self, from: jws.payload) + let payload = try JSONDecoder.jwt.decode(C.self, from: jws.payload) guard try jws.verify(key: senderKey) else { throw JWTError.invalidSignature @@ -95,7 +95,7 @@ extension JWT { expectedAudience: expectedAudience ) } - let payload = try JSONDecoder().decode(C.self, from: decryptedPayload) + let payload = try JSONDecoder.jwt.decode(C.self, from: decryptedPayload) return .init(payload: payload, format: .jwe(jwe)) default: throw JWTError.somethingWentWrong diff --git a/Sources/JSONWebToken/JWT.swift b/Sources/JSONWebToken/JWT.swift index e2b6ee0..1ceb386 100644 --- a/Sources/JSONWebToken/JWT.swift +++ b/Sources/JSONWebToken/JWT.swift @@ -66,7 +66,7 @@ public struct JWT { public extension JWT { static func getPayload(jwtString: String) throws -> Payload { - return try JSONDecoder().decode(Payload.self, from: getPayload(jwtString: jwtString)) + return try JSONDecoder.jwt.decode(Payload.self, from: getPayload(jwtString: jwtString)) } static func getPayload(jwtString: String) throws -> Data { diff --git a/Sources/Tools/JWTCodable.swift b/Sources/Tools/JWTCodable.swift new file mode 100644 index 0000000..1a5f31c --- /dev/null +++ b/Sources/Tools/JWTCodable.swift @@ -0,0 +1,34 @@ +/* + * Copyright 2024 Gonçalo Frade + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with 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 JSONEncoder { + public static var jwt: JSONEncoder { + let encoder = JSONEncoder() + encoder.outputFormatting = [.sortedKeys, .withoutEscapingSlashes] + encoder.dateEncodingStrategy = .secondsSince1970 + return encoder + } +} + +extension JSONDecoder { + public static var jwt: JSONDecoder { + let decoder = JSONDecoder() + decoder.dateDecodingStrategy = .secondsSince1970 + return decoder + } +} diff --git a/Tests/JWTTests/JWTTests.swift b/Tests/JWTTests/JWTTests.swift index 9f49df1..462c541 100644 --- a/Tests/JWTTests/JWTTests.swift +++ b/Tests/JWTTests/JWTTests.swift @@ -7,7 +7,7 @@ final class JWTTests: XCTestCase { func testParseSignedJWT() throws { let jwtString = """ - eyJhbGciOiJub25lIn0.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ. + eyJhbGciOiJub25lIn0.eyJpc3MiOiJ0ZXN0QWxpY2UiLCJzdWIiOiJBbGljZSIsInRlc3RDbGFpbSI6InRlc3RlZENsYWltIn0. """ let jwt = try JWT.verify(jwtString: jwtString) @@ -20,13 +20,11 @@ final class JWTTests: XCTestCase { XCTFail("Wrong JWT format") } - let expirationTime = jwt.payload.exp?.timeIntervalSince1970 - XCTAssertEqual(jwt.payload.iss, "joe") - XCTAssertEqual(jwt.payload.exp!, Date(timeIntervalSince1970: 2279126580.0)) + XCTAssertEqual(jwt.payload.iss, "testAlice") } func testSignAndVerify() throws { - let issuedAt = Date(timeIntervalSince1970: 0) + let issuedAt = Date(timeIntervalSince1970: 200) let mockClaims = MockExampleClaims( iss: "testAlice", sub: "Alice", @@ -45,7 +43,7 @@ final class JWTTests: XCTestCase { let jwtString = jwt.jwtString XCTAssertTrue(jwtString.contains("eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9")) - XCTAssertTrue(jwtString.contains("eyJpYXQiOi05NzgzMDcyMDAsImlzcyI6InRlc3RBbGljZSIsInN1YiI6IkFsaWNlIiwidGVzdENsYWltIjoidGVzdGVkQ2xhaW0ifQ")) + XCTAssertTrue(jwtString.contains("eyJpYXQiOjIwMCwiaXNzIjoidGVzdEFsaWNlIiwic3ViIjoiQWxpY2UiLCJ0ZXN0Q2xhaW0iOiJ0ZXN0ZWRDbGFpbSJ9")) let verifiedJWT = try JWT.verify(jwtString: jwtString, senderKey: key) let verifiedPayload = verifiedJWT.payload @@ -150,7 +148,6 @@ final class JWTTests: XCTestCase { } func testFailAudienceValidation() throws { - let nbf = Date(timeIntervalSinceNow: 1000) let mockClaims = DefaultJWTClaimsImpl( iss: "testAlice", sub: "Alice",