Skip to content

Commit 1a0a148

Browse files
authored
Make JWTDecodeError conform to Sendable (#263)
1 parent c00978d commit 1a0a148

File tree

2 files changed

+50
-40
lines changed

2 files changed

+50
-40
lines changed

JWTDecode/JWTDecodeError.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import Foundation
22

33
/// A decoding error due to a malformed JWT.
4-
public enum JWTDecodeError: LocalizedError, CustomDebugStringConvertible {
4+
public enum JWTDecodeError: LocalizedError, CustomDebugStringConvertible, Sendable {
55
/// When either the header or body parts cannot be Base64URL-decoded.
66
case invalidBase64URL(String)
77

JWTDecodeTests/JWTDecodeSpec.swift

Lines changed: 49 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,17 @@ import JWTDecode
33
import Foundation
44

55
class JWTDecodeSpec: XCTestCase {
6-
6+
77
func testExpiredJWT() {
88
let sut = expiredJWT()
99
XCTAssertTrue(sut.expired)
1010
}
11-
11+
1212
func testNonExpiredJWT() {
1313
let sut = nonExpiredJWT()
1414
XCTAssertFalse(sut.expired)
1515
}
16-
16+
1717
func testExpiredJWTWithCloseEnoughTimestamp() {
1818
let sut = jwtThatExpiresAt(date: Date())
1919
XCTAssertTrue(sut.expired)
@@ -34,91 +34,91 @@ class JWTDecodeSpec: XCTestCase {
3434
let payload = jwt.body as! [String: String]
3535
XCTAssertEqual(payload, ["sub": "myid", "name": "Shawarma Monk"])
3636
}
37-
37+
3838
func testReturnOriginalJWTStringRepresentation() {
3939
let jwtString = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJjb20uc29td2hlcmUuZmFyLmJleW9uZDphcGki"
4040
+ "LCJpc3MiOiJhdXRoMCIsInVzZXJfcm9sZSI6ImFkbWluIn0.sS84motSLj9HNTgrCPcAjgZIQ99jXNN7_W9fEIIfxz0"
4141
let jwt = try! decode(jwt: jwtString)
4242
XCTAssertEqual(jwt.string, jwtString)
4343
}
44-
44+
4545
func testReturnExpireDate() {
4646
let sut = expiredJWT()
4747
XCTAssertNotNil(sut.expiresAt)
4848
}
49-
49+
5050
func testDecodeValidJWT() {
5151
let jwtString = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJjb20uc29td2hlcmUuZmFyLmJleW9uZDphcGki"
5252
+ "LCJpc3MiOiJhdXRoMCIsInVzZXJfcm9sZSI6ImFkbWluIn0.sS84motSLj9HNTgrCPcAjgZIQ99jXNN7_W9fEIIfxz0"
5353
XCTAssertNotNil(try! decode(jwt: jwtString))
5454
}
55-
55+
5656
func testDecodeValidJWTWithEmptyJSONBody() {
5757
let jwtString = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.Et9HFtf9R3GEMA0IICOfFMVXY7kkTX1wr4qCyhIf58U"
5858
XCTAssertNotNil(try! decode(jwt: jwtString))
5959
}
60-
60+
6161
func testRaiseExceptionWithInvalidBase64Encoding() {
6262
let invalidChar = "%"
6363
let jwtString = "\(invalidChar).BODY.SIGNATURE"
6464
XCTAssertThrowsError(try decode(jwt: jwtString)) { error in
6565
XCTAssertEqual(error as? JWTDecodeError, .invalidBase64URL(invalidChar))
6666
}
6767
}
68-
68+
6969
func testRaiseExceptionWithInvalidJSONInJWT() {
7070
let jwtString = "HEADER.BODY.SIGNATURE"
7171
XCTAssertThrowsError(try decode(jwt: jwtString)) { error in
7272
XCTAssertEqual(error as? JWTDecodeError, .invalidJSON("HEADER"))
7373
}
7474
}
75-
75+
7676
func testRaiseExceptionWithMissingParts() {
7777
let jwtString = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJzdWIifQ"
7878
XCTAssertThrowsError(try decode(jwt: jwtString)) { error in
7979
XCTAssertEqual(error as? JWTDecodeError, .invalidPartCount(jwtString, 2))
8080
}
8181
}
82-
82+
8383
func testReturnHeader() {
8484
let jwtString = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJzdWIifQ.xXcD7WOvUDHJ94E6aVHYgXdsJHLl2oW7Z"
8585
+ "Xm4QpVvXnY"
8686
let sut = try! decode(jwt: jwtString)
8787
XCTAssertEqual(sut.header as? [String: String], ["alg": "HS256", "typ": "JWT"])
8888
}
89-
89+
9090
func testReturnBody() {
9191
let jwtString = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJzdWIifQ.xXcD7WOvUDHJ94E6aVHYgXdsJHLl2oW7Z"
9292
+ "Xm4QpVvXnY"
9393
let sut = try! decode(jwt: jwtString)
9494
XCTAssertEqual(sut.body as? [String: String], ["sub": "sub"])
9595
}
96-
96+
9797
func testReturnSignature() {
9898
let jwtString = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJzdWIifQ.xXcD7WOvUDHJ94E6aVHYgXdsJHLl2oW7Z"
9999
+ "Xm4QpVvXnY"
100100
let sut = try! decode(jwt: jwtString)
101101
XCTAssertEqual(sut.signature, "xXcD7WOvUDHJ94E6aVHYgXdsJHLl2oW7ZXm4QpVvXnY")
102102
}
103-
103+
104104
func testExpiresAtClaimExpiredJWT() {
105105
let sut = expiredJWT()
106106
XCTAssertNotNil(sut.expiresAt)
107107
XCTAssertTrue(sut.expired)
108108
}
109-
109+
110110
func testExpiresAtClaimNonExpiredJWT() {
111111
let sut = nonExpiredJWT()
112112
XCTAssertNotNil(sut.expiresAt)
113113
XCTAssertFalse(sut.expired)
114114
}
115-
115+
116116
func testExpiresAtClaimJWTWithoutExpiresAtClaim() {
117117
let sut = jwt(withBody: ["sub": UUID().uuidString])
118118
XCTAssertNil(sut.expiresAt)
119119
XCTAssertFalse(sut.expired)
120120
}
121-
121+
122122
func testIssuerClaim() {
123123
let jwtString = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL2V4YW1wbGUudXMuYXV0aDAuY29t"
124124
+ "Iiwic3ViIjoiYXV0aDB8MTAxMDEwMTAxMCIsImF1ZCI6Imh0dHBzOi8vZXhhbXBsZS51cy5hdXRoMC5jb20iLCJleHAiOjE"
@@ -127,7 +127,7 @@ class JWTDecodeSpec: XCTestCase {
127127
let sut = try! decode(jwt: jwtString)
128128
XCTAssertEqual(sut.issuer, "https://example.us.auth0.com")
129129
}
130-
130+
131131
func testSubjectClaim() {
132132
let jwtString = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL2V4YW1wbGUudXMuYXV0aDAuY29t"
133133
+ "Iiwic3ViIjoiYXV0aDB8MTAxMDEwMTAxMCIsImF1ZCI6Imh0dHBzOi8vZXhhbXBsZS51cy5hdXRoMC5jb20iLCJleHAiOjE"
@@ -136,7 +136,7 @@ class JWTDecodeSpec: XCTestCase {
136136
let sut = try! decode(jwt: jwtString)
137137
XCTAssertEqual(sut.subject, "auth0|1010101010")
138138
}
139-
139+
140140
func testSingleAudienceClaim() {
141141
let jwtString = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL2V4YW1wbGUudXMuYXV0aDAuY29t"
142142
+ "Iiwic3ViIjoiYXV0aDB8MTAxMDEwMTAxMCIsImF1ZCI6Imh0dHBzOi8vZXhhbXBsZS51cy5hdXRoMC5jb20iLCJleHAiOjE"
@@ -145,15 +145,15 @@ class JWTDecodeSpec: XCTestCase {
145145
let sut = try! decode(jwt: jwtString)
146146
XCTAssertEqual(sut.audience, ["https://example.us.auth0.com"])
147147
}
148-
148+
149149
func testMultipleAudiencesClaim() {
150150
let jwtString = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiaHR0cHM6Ly9leGFtcGxlLnVzLmF1dGgw"
151151
+ "LmNvbSIsImh0dHBzOi8vYXBpLmV4YW1wbGUudXMuYXV0aDAuY29tIl19.sw24la9mmCmykudpyE-U1Ar5bbyuDMyKaW"
152152
+ "ksSkBXhrM"
153153
let sut = try! decode(jwt: jwtString)
154154
XCTAssertEqual(sut.audience, ["https://example.us.auth0.com", "https://api.example.us.auth0.com"])
155155
}
156-
156+
157157
func testIssuedAtClaim() {
158158
let jwtString = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL2V4YW1wbGUudXMuYXV0aDAuY29t"
159159
+ "Iiwic3ViIjoiYXV0aDB8MTAxMDEwMTAxMCIsImF1ZCI6Imh0dHBzOi8vZXhhbXBsZS51cy5hdXRoMC5jb20iLCJleHAiOjE"
@@ -162,7 +162,7 @@ class JWTDecodeSpec: XCTestCase {
162162
let sut = try! decode(jwt: jwtString)
163163
XCTAssertEqual(sut.issuedAt, Date(timeIntervalSince1970: 1372638336))
164164
}
165-
165+
166166
func testNotBeforeClaim() {
167167
let jwtString = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL2V4YW1wbGUudXMuYXV0aDAuY29t"
168168
+ "Iiwic3ViIjoiYXV0aDB8MTAxMDEwMTAxMCIsImF1ZCI6Imh0dHBzOi8vZXhhbXBsZS51cy5hdXRoMC5jb20iLCJleHAiOjE"
@@ -171,7 +171,7 @@ class JWTDecodeSpec: XCTestCase {
171171
let sut = try! decode(jwt: jwtString)
172172
XCTAssertEqual(sut.notBefore, Date(timeIntervalSince1970: 1372638336))
173173
}
174-
174+
175175
func testJWTIdClaim() {
176176
let jwtString = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL2V4YW1wbGUudXMuYXV0aDAuY29t"
177177
+ "Iiwic3ViIjoiYXV0aDB8MTAxMDEwMTAxMCIsImF1ZCI6Imh0dHBzOi8vZXhhbXBsZS51cy5hdXRoMC5jb20iLCJleHAiOjE"
@@ -180,7 +180,7 @@ class JWTDecodeSpec: XCTestCase {
180180
let sut = try! decode(jwt: jwtString)
181181
XCTAssertEqual(sut.identifier, "qwerty123456")
182182
}
183-
183+
184184
func testClaimByName() {
185185
let sut = jwt(withBody: ["sub": UUID().uuidString,
186186
"custom_string_claim": "Shawarma Friday!",
@@ -191,7 +191,7 @@ class JWTDecodeSpec: XCTestCase {
191191
let claim = sut.claim(name: "custom_string_claim")
192192
XCTAssertNotNil(claim.rawValue)
193193
}
194-
194+
195195
func testCustomStringClaim() {
196196
let sut = jwt(withBody: ["sub": UUID().uuidString,
197197
"custom_string_claim": "Shawarma Friday!",
@@ -208,7 +208,7 @@ class JWTDecodeSpec: XCTestCase {
208208
XCTAssertNil(claim.date)
209209
XCTAssertNil(claim.boolean)
210210
}
211-
211+
212212
func testCustomIntegerClaim() {
213213
let sut = jwt(withBody: ["sub": UUID().uuidString,
214214
"custom_string_claim": "Shawarma Friday!",
@@ -224,7 +224,7 @@ class JWTDecodeSpec: XCTestCase {
224224
XCTAssertEqual(claim.date, Date(timeIntervalSince1970: 10))
225225
XCTAssertNil(claim.boolean)
226226
}
227-
227+
228228
func testCustomIntegerClaim0() {
229229
let sut = jwt(withBody: ["sub": UUID().uuidString,
230230
"custom_string_claim": "Shawarma Friday!",
@@ -240,7 +240,7 @@ class JWTDecodeSpec: XCTestCase {
240240
XCTAssertEqual(claim.date, Date(timeIntervalSince1970: 0))
241241
XCTAssertNil(claim.boolean)
242242
}
243-
243+
244244
func testCustomIntegerClaim1() {
245245
let sut = jwt(withBody: ["sub": UUID().uuidString,
246246
"custom_string_claim": "Shawarma Friday!",
@@ -256,7 +256,7 @@ class JWTDecodeSpec: XCTestCase {
256256
XCTAssertEqual(claim.date, Date(timeIntervalSince1970: 1))
257257
XCTAssertNil(claim.boolean)
258258
}
259-
259+
260260
func testCustomIntegerClaimString() {
261261
let sut = jwt(withBody: ["sub": UUID().uuidString,
262262
"custom_string_claim": "Shawarma Friday!",
@@ -272,7 +272,7 @@ class JWTDecodeSpec: XCTestCase {
272272
XCTAssertEqual(claim.date, Date(timeIntervalSince1970: 13))
273273
XCTAssertNil(claim.boolean)
274274
}
275-
275+
276276
func testCustomDoubleClaim() {
277277
let sut = jwt(withBody: ["sub": UUID().uuidString,
278278
"custom_string_claim": "Shawarma Friday!",
@@ -289,7 +289,7 @@ class JWTDecodeSpec: XCTestCase {
289289
XCTAssertEqual(claim.date, Date(timeIntervalSince1970: 3.1))
290290
XCTAssertNil(claim.boolean)
291291
}
292-
292+
293293
func testCustomDoubleClaim0() {
294294
let sut = jwt(withBody: ["sub": UUID().uuidString,
295295
"custom_string_claim": "Shawarma Friday!",
@@ -306,7 +306,7 @@ class JWTDecodeSpec: XCTestCase {
306306
XCTAssertEqual(claim.date, Date(timeIntervalSince1970: 0))
307307
XCTAssertNil(claim.boolean)
308308
}
309-
309+
310310
func testCustomDoubleClaim1() {
311311
let sut = jwt(withBody: ["sub": UUID().uuidString,
312312
"custom_string_claim": "Shawarma Friday!",
@@ -323,7 +323,7 @@ class JWTDecodeSpec: XCTestCase {
323323
XCTAssertEqual(claim.date, Date(timeIntervalSince1970: 1))
324324
XCTAssertNil(claim.boolean)
325325
}
326-
326+
327327
func testCustomDoubleClaimString() {
328328
let sut = jwt(withBody: ["sub": UUID().uuidString,
329329
"custom_string_claim": "Shawarma Friday!",
@@ -340,7 +340,7 @@ class JWTDecodeSpec: XCTestCase {
340340
XCTAssertEqual(claim.date, Date(timeIntervalSince1970: 1.3))
341341
XCTAssertNil(claim.boolean)
342342
}
343-
343+
344344
func testCustomBooleanClaimTrue() {
345345
let sut = jwt(withBody: ["sub": UUID().uuidString,
346346
"custom_string_claim": "Shawarma Friday!",
@@ -357,7 +357,7 @@ class JWTDecodeSpec: XCTestCase {
357357
XCTAssertNil(claim.date)
358358
XCTAssertEqual(claim.boolean, true)
359359
}
360-
360+
361361
func testCustomBooleanClaimFalse() {
362362
let sut = jwt(withBody: ["sub": UUID().uuidString,
363363
"custom_string_claim": "Shawarma Friday!",
@@ -374,7 +374,7 @@ class JWTDecodeSpec: XCTestCase {
374374
XCTAssertNil(claim.date)
375375
XCTAssertEqual(claim.boolean, false)
376376
}
377-
377+
378378
func testMissingClaim() {
379379
let sut = jwt(withBody: ["sub": UUID().uuidString,
380380
"custom_string_claim": "Shawarma Friday!",
@@ -390,21 +390,31 @@ class JWTDecodeSpec: XCTestCase {
390390
XCTAssertNil(unknownClaim.date)
391391
XCTAssertNil(unknownClaim.boolean)
392392
}
393-
393+
394394
func testRawClaimEmail() {
395395
let jwtString = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3NhbXBsZXMuYXV0aDAuY29tIiwic3ViIjoiYXV0aDB8MTAxMDEwMTAxMCIsImF1ZCI6Imh0dHBzOi8vc2FtcGxlcy5hdXRoMC5jb20iLCJleHAiOjEzNzI2NzQzMzYsImlhdCI6MTM3MjYzODMzNiwianRpIjoicXdlcnR5MTIzNDU2IiwibmJmIjoxMzcyNjM4MzM2LCJlbWFpbCI6InVzZXJAaG9zdC5jb20iLCJjdXN0b20iOlsxLDIsM119.JeMRyHLkcoiqGxd958B6PABKNvhOhIgw-kbjecmhR_E"
396396
let sut = try! decode(jwt: jwtString)
397-
XCTAssertEqual(sut["email"].string, "[email protected]")
397+
XCTAssertEqual(sut["email"].rawValue as? String, "[email protected]")
398398
}
399-
399+
400400
func testRawClaimArray() {
401401
let jwtString = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3NhbXBsZXMuYXV0aDAuY29tIiwic3ViIjoiYXV0aDB8MTAxMDEwMTAxMCIsImF1ZCI6Imh0dHBzOi8vc2FtcGxlcy5hdXRoMC5jb20iLCJleHAiOjEzNzI2NzQzMzYsImlhdCI6MTM3MjYzODMzNiwianRpIjoicXdlcnR5MTIzNDU2IiwibmJmIjoxMzcyNjM4MzM2LCJlbWFpbCI6InVzZXJAaG9zdC5jb20iLCJjdXN0b20iOlsxLDIsM119.JeMRyHLkcoiqGxd958B6PABKNvhOhIgw-kbjecmhR_E"
402402
let sut = try! decode(jwt: jwtString)
403403
XCTAssertNotNil(sut["custom"].rawValue as? [Int])
404404
}
405+
406+
func testRawClaimDict() {
407+
let jwtString = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3NhbXBsZXMuYXV0aDAuY29tIiwic3ViIjoiYXV0aDB8MTAxMDEwMTAxMCIsImF1ZCI6Imh0dHBzOi8vc2FtcGxlcy5hdXRoMC5jb20iLCJleHAiOjEzNzI2NzQzMzYsImlhdCI6MTM3MjYzODMzNiwianRpIjoicXdlcnR5MTIzNDU2IiwibmJmIjoxMzcyNjM4MzM2LCJlbWFpbCI6InVzZXJAaG9zdC5jb20iLCJjdXN0b20iOnsiZm9vIjoiYmFyIiwiYmF6IjoxMjN9fQ.scStGGBQrySWIeJEoCgHhx7fUQT-ciUGG_itliv1nKQ"
408+
let sut = try! decode(jwt: jwtString)
409+
XCTAssertNotNil(sut["custom"].rawValue as? [String: Any])
410+
}
405411
}
406412

413+
#if compiler(>=6.0)
414+
extension JWTDecodeError: @retroactive Equatable {}
415+
#else
407416
extension JWTDecodeError: Equatable {}
417+
#endif
408418

409419
public func ==(lhs: JWTDecodeError, rhs: JWTDecodeError) -> Bool {
410420
return lhs.localizedDescription == rhs.localizedDescription && lhs.errorDescription == rhs.errorDescription

0 commit comments

Comments
 (0)