Skip to content

Remove deprecated encode/decode methods, fix warnings and other… #112

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 25 commits into from
Sep 23, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
7f42251
Remove CommonCrypto directory as Swift 4.2 no longer requires this
jonblatho Jul 23, 2018
8004906
Correct encoding unit tests to account for unordered Swift dictionaries
jonblatho Jul 23, 2018
398c825
Reindent to match existing style
jonblatho Jul 23, 2018
ec735aa
Fix warning about deallocate(capacity:) deprecation
jonblatho Jul 23, 2018
264a622
Update many unit tests to stop using deprecated decode method
jonblatho Jul 23, 2018
61e4cd7
Fix remaining unit tests
jonblatho Jul 24, 2018
14ddad4
Bump CryptoSwift to 0.10.0
jonblatho Jul 24, 2018
2ab9490
Correct misspelled method name for validateExpiry(leeway:), retain ol…
jonblatho Jul 24, 2018
312dce7
Remove deprecated encode/decode methods
jonblatho Jul 24, 2018
30677df
Undo removal of CommonCrypto; will try to find compatible solution be…
jonblatho Jul 24, 2018
884e032
Merge pull request #1 from jonblatho/swift-4.2
jonblatho Jul 24, 2018
662871d
see if stripping down the Travis config gets builds working on macOS …
jonblatho Jul 24, 2018
47a8b7f
try adding Ubuntu back into Travis builds
jonblatho Jul 24, 2018
1135108
Travis doesn’t support Xenial, back to Trusty
jonblatho Jul 24, 2018
a50823d
getting closer to original config
jonblatho Jul 24, 2018
44d6d59
Sync up LinuxMain.swift (hopefully)
jonblatho Jul 24, 2018
8d1482a
Merge pull request #2 from jonblatho/swift-4.2
jonblatho Jul 24, 2018
32b7b6e
Fix LinuxMain.swift typo
jonblatho Jul 24, 2018
65dfb1a
See if converting TimeInterval/Double to Int might help Travis builds…
jonblatho Jul 24, 2018
f2bbd1d
See if explicitly handling Ints in parsing JWT times fixes Ubuntu builds
jonblatho Jul 24, 2018
4b83583
simplify Travis config to use swift test only
jonblatho Jul 24, 2018
708c7a7
Correct misspelled unit test method name
jonblatho Jul 24, 2018
44f4b7a
Fix for CommonCrypto inclusion in Swift 4.2
jonblatho Jul 24, 2018
898f0c8
Add podspec
jonblatho Aug 7, 2018
50b7757
Delete JSONWebToken.podspec
jonblatho Aug 7, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 3 additions & 9 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
os:
- osx
- linux
osx_image: xcode9
osx_image: xcode9.4
language: generic
sudo: required
dist: trusty

env:
global:
- SWIFT_VERSION=4.0
- SWIFT_VERSION=4.1.2
matrix:
- SWIFTPM_BUILD=true
- SWIFTPM_TEST=true
- XCODE_TEST_SDK=macosx
- XCODE_BUILD_SDK=iphonesimulator
Expand All @@ -18,12 +19,6 @@ env:

matrix:
exclude:
# No need to build and test on macOS
- os: osx
env: SWIFTPM_BUILD=true
# LinuxMain.swift is out of sync
- os: linux
env: SWIFTPM_TEST=true
- os: linux
env: XCODE_TEST_SDK=macosx
- os: linux
Expand All @@ -37,7 +32,6 @@ install:
- eval "$(curl -sL https://swiftenv.fuller.li/install.sh)"

script:
- if [ -n "$SWIFTPM_BUILD" ]; then swift build; fi
- if [ -n "$SWIFTPM_TEST" ]; then swift test; fi
- if [ -n "$XCODE_BUILD_SDK" ] || [ -n "$XCODE_TEST_SDK" ]; then swift package generate-xcodeproj; fi
- if [ -n "$XCODE_BUILD_SDK" ]; then xcodebuild -project JWT.xcodeproj -scheme JWT-Package build -sdk $XCODE_BUILD_SDK; fi
Expand Down
6 changes: 5 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,18 @@ import PackageDescription


#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
#if canImport(CommonCrypto)
let dependencies: [Package.Dependency] = []
#else
let dependencies = [
Package.Dependency.package(url: "https://github.com/kylef-archive/CommonCrypto.git", from: "1.0.0"),
]
#endif
let excludes = ["HMAC/HMACCryptoSwift.swift"]
let targetDependencies: [Target.Dependency] = []
#else
let dependencies = [
Package.Dependency.package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", from: "0.8.0"),
Package.Dependency.package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", from: "0.10.0"),
]
let excludes = ["HMAC/HMACCommonCrypto.swift"]
let targetDependencies: [Target.Dependency] = ["CryptoSwift"]
Expand Down
2 changes: 1 addition & 1 deletion Sources/JWA/HMAC/HMACCommonCrypto.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import CommonCrypto
extension HMACAlgorithm: SignAlgorithm, VerifyAlgorithm {
public func sign(_ message: Data) -> Data {
let context = UnsafeMutablePointer<CCHmacContext>.allocate(capacity: 1)
defer { context.deallocate(capacity: 1) }
defer { context.deallocate() }

key.withUnsafeBytes() { (buffer: UnsafePointer<UInt8>) in
CCHmacInit(context, hash.commonCryptoAlgorithm, buffer, size_t(key.count))
Expand Down
14 changes: 12 additions & 2 deletions Sources/JWT/ClaimSet.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ func parseTimeInterval(_ value: Any?) -> Date? {
if let string = value as? String, let interval = TimeInterval(string) {
return Date(timeIntervalSince1970: interval)
}

if let interval = value as? Int {
let double = Double(interval)
return Date(timeIntervalSince1970: double)
}

if let interval = value as? TimeInterval {
return Date(timeIntervalSince1970: interval)
Expand Down Expand Up @@ -104,7 +109,7 @@ extension ClaimSet {
try validateAudience(audience)
}

try validateExpiary(leeway: leeway)
try validateExpiry(leeway: leeway)
try validateNotBefore(leeway: leeway)
try validateIssuedAt(leeway: leeway)
}
Expand Down Expand Up @@ -132,8 +137,13 @@ extension ClaimSet {
throw InvalidToken.invalidIssuer
}
}


@available(*, deprecated, message: "This method's name is misspelled. Please instead use validateExpiry(leeway:).")
public func validateExpiary(leeway: TimeInterval = 0) throws {
try validateExpiry(leeway: leeway)
}

public func validateExpiry(leeway: TimeInterval = 0) throws {
try validateDate(claims, key: "exp", comparison: .orderedAscending, leeway: (-1 * leeway), failure: .expiredSignature, decodeError: "Expiration time claim (exp) must be an integer")
}

Expand Down
12 changes: 0 additions & 12 deletions Sources/JWT/Decode.swift
Original file line number Diff line number Diff line change
Expand Up @@ -63,18 +63,6 @@ public func decode(_ jwt: String, algorithm: Algorithm, verify: Bool = true, aud
return try decode(jwt, algorithms: [algorithm], verify: verify, audience: audience, issuer: issuer, leeway: leeway)
}

/// Decode a JWT
@available(*, deprecated, message: "use decode that returns a ClaimSet instead")
public func decode(_ jwt: String, algorithms: [Algorithm], verify: Bool = true, audience: String? = nil, issuer: String? = nil) throws -> Payload {
return try decode(jwt, algorithms: algorithms, verify: verify, audience: audience, issuer: issuer).claims
}

/// Decode a JWT
@available(*, deprecated, message: "use decode that returns a ClaimSet instead")
public func decode(_ jwt: String, algorithm: Algorithm, verify: Bool = true, audience: String? = nil, issuer: String? = nil) throws -> Payload {
return try decode(jwt, algorithms: [algorithm], verify: verify, audience: audience, issuer: issuer).claims
}

// MARK: Parsing a JWT

func load(_ jwt: String) throws -> (header: JOSEHeader, payload: ClaimSet, signature: Data, signatureInput: String) {
Expand Down
11 changes: 0 additions & 11 deletions Sources/JWT/Encode.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,3 @@ public func encode(_ algorithm: Algorithm, closure: ((ClaimSetBuilder) -> Void))
closure(builder)
return encode(claims: builder.claims, algorithm: algorithm)
}


/*** Encode a payload
- parameter payload: The payload to sign
- parameter algorithm: The algorithm to sign the payload with
- returns: The JSON web token as a String
*/
@available(*, deprecated, message: "use encode(claims: algorithm:) instead")
public func encode(_ payload: Payload, algorithm: Algorithm) -> String {
return encode(claims: ClaimSet(claims: payload), algorithm: algorithm)
}
4 changes: 2 additions & 2 deletions Tests/JWTTests/ClaimSetTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ class ValidationTests: XCTestCase {
claims.expiration = Date().addingTimeInterval(-1)

do {
try claims.validateExpiary()
try claims.validateExpiry()
XCTFail("InvalidToken.expiredSignature error should have been thrown.")
} catch InvalidToken.expiredSignature {
// Correct error thrown
Expand All @@ -21,7 +21,7 @@ class ValidationTests: XCTestCase {
claims.expiration = Date().addingTimeInterval(-1)

do {
try claims.validateExpiary(leeway: 2)
try claims.validateExpiry(leeway: 2)
} catch {
XCTFail("Unexpected error while validating exp claim that should be valid with leeway.")
}
Expand Down
45 changes: 19 additions & 26 deletions Tests/JWTTests/JWTDecodeTests.swift
Original file line number Diff line number Diff line change
@@ -1,19 +1,12 @@
import Foundation
import XCTest
import JWT
@testable import JWT

class DecodeTests: XCTestCase {
func testDecodingValidJWTAsClaimSet() throws {
let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiS3lsZSJ9.zxm7xcp1eZtZhp4t-nlw09ATQnnFKIiSN83uG8u6cAg"

let claims: ClaimSet = try JWT.decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))
XCTAssertEqual(claims["name"] as? String, "Kyle")
}

func testDecodingValidJWT() throws {
let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiS3lsZSJ9.zxm7xcp1eZtZhp4t-nlw09ATQnnFKIiSN83uG8u6cAg"

let claims: ClaimSet = try JWT.decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))
let claims = try JWT.decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))
XCTAssertEqual(claims["name"] as? String, "Kyle")
}

Expand All @@ -25,15 +18,15 @@ class DecodeTests: XCTestCase {

func testDisablingVerify() throws {
let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.2_8pWJfyPup0YwOXK7g9Dn0cF1E3pdn299t4hSeJy5w"
_ = try decode(jwt, algorithm: .none, verify: false, issuer: "fuller.li") as ClaimSet
_ = try decode(jwt, algorithm: .none, verify: false, issuer: "fuller.li")
}

// MARK: Issuer claim

func testSuccessfulIssuerValidation() throws {
let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJmdWxsZXIubGkifQ.d7B7PAQcz1E6oNhrlxmHxHXHgg39_k7X7wWeahl8kSQ"

let claims: ClaimSet = try JWT.decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))
let claims = try JWT.decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))
XCTAssertEqual(claims.issuer, "fuller.li")
}

Expand All @@ -54,7 +47,7 @@ class DecodeTests: XCTestCase {
XCTAssertThrowsError(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!)))
}

func testInvalidExpiaryClaim() {
func testInvalidExpiryClaim() {
let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOlsiMTQyODE4ODQ5MSJdfQ.OwF-wd3THjxrEGUhh6IdnNhxQZ7ydwJ3Z6J_dfl9MBs"
XCTAssertThrowsError(try decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!)))
}
Expand All @@ -63,15 +56,15 @@ class DecodeTests: XCTestCase {
// If this just started failing, hello 2024!
let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MjgxODg0OTF9.EW7k-8Mvnv0GpvOKJalFRLoCB3a3xGG3i7hAZZXNAz0"

let claims: ClaimSet = try JWT.decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))
XCTAssertEqual(claims.expiration?.timeIntervalSince1970, 1728188491)
let claims = try JWT.decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))
XCTAssertEqual(claims.expiration?.timeIntervalSince1970, 1728188491)
}

func testUnexpiredClaimString() throws {
// If this just started failing, hello 2024!
let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOiIxNzI4MTg4NDkxIn0.y4w7lNLrfRRPzuNUfM-ZvPkoOtrTU_d8ZVYasLdZGpk"

let claims: ClaimSet = try JWT.decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))
let claims = try JWT.decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))
XCTAssertEqual(claims.expiration?.timeIntervalSince1970, 1728188491)
}

Expand All @@ -80,14 +73,14 @@ class DecodeTests: XCTestCase {
func testNotBeforeClaim() throws {
let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE0MjgxODk3MjB9.jFT0nXAJvEwyG6R7CMJlzNJb7FtZGv30QRZpYam5cvs"

let claims: ClaimSet = try JWT.decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))
let claims = try JWT.decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))
XCTAssertEqual(claims.notBefore?.timeIntervalSince1970, 1428189720)
}

func testNotBeforeClaimString() throws {
let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOiIxNDI4MTg5NzIwIn0.qZsj36irdmIAeXv6YazWDSFbpuxHtEh4Deof5YTpnVI"

let claims: ClaimSet = try JWT.decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))
let claims = try JWT.decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))
XCTAssertEqual(claims.notBefore?.timeIntervalSince1970, 1428189720)
}

Expand All @@ -107,14 +100,14 @@ class DecodeTests: XCTestCase {
func testIssuedAtClaimInThePast() throws {
let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE0MjgxODk3MjB9.I_5qjRcCUZVQdABLwG82CSuu2relSdIyJOyvXWUAJh4"

let claims: ClaimSet = try JWT.decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))
let claims = try JWT.decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))
XCTAssertEqual(claims.issuedAt?.timeIntervalSince1970, 1428189720)
}

func testIssuedAtClaimInThePastString() throws {
let jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOiIxNDI4MTg5NzIwIn0.M8veWtsY52oBwi7LRKzvNnzhjK0QBS8Su1r0atlns2k"

let claims: ClaimSet = try JWT.decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))
let claims = try JWT.decode(jwt, algorithm: .hs256("secret".data(using: .utf8)!))
XCTAssertEqual(claims.issuedAt?.timeIntervalSince1970, 1428189720)
}

Expand Down Expand Up @@ -185,24 +178,24 @@ class DecodeTests: XCTestCase {

func testHS512Algorithm() {
let jwt = "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJzb21lIjoicGF5bG9hZCJ9.WTzLzFO079PduJiFIyzrOah54YaM8qoxH9fLMQoQhKtw3_fMGjImIOokijDkXVbyfBqhMo2GCNu4w9v7UXvnpA"
assertSuccess(try decode(jwt, algorithm: .hs512("secret".data(using: .utf8)!))) { payload in
XCTAssertEqual(payload as! [String: String], ["some": "payload"])
assertSuccess(try decode(jwt, algorithm: .hs512("secret".data(using: .utf8)!))) { claims in
XCTAssertEqual(claims as! [String: String], ["some": "payload"])
}
}
}

// MARK: Helpers

func assertSuccess(_ decoder: @autoclosure () throws -> Payload, closure: ((Payload) -> Void)? = nil) {
func assertSuccess(_ decoder: @autoclosure () throws -> ClaimSet, closure: (([String: Any]) -> Void)? = nil) {
do {
let payload = try decoder()
closure?(payload)
let claims = try decoder()
closure?(claims.claims as [String: Any])
} catch {
XCTFail("Failed to decode while expecting success. \(error)")
}
}

func assertFailure(_ decoder: @autoclosure () throws -> Payload, closure: ((InvalidToken) -> Void)? = nil) {
func assertFailure(_ decoder: @autoclosure () throws -> ClaimSet, closure: ((InvalidToken) -> Void)? = nil) {
do {
_ = try decoder()
XCTFail("Decoding succeeded, expected a failure.")
Expand All @@ -213,7 +206,7 @@ func assertFailure(_ decoder: @autoclosure () throws -> Payload, closure: ((Inva
}
}

func assertDecodeError(_ decoder: @autoclosure () throws -> Payload, error: String) {
func assertDecodeError(_ decoder: @autoclosure () throws -> ClaimSet, error: String) {
assertFailure(try decoder()) { failure in
switch failure {
case .decodeError(let decodeError):
Expand Down
42 changes: 32 additions & 10 deletions Tests/JWTTests/JWTEncodeTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,31 +6,53 @@ class JWTEncodeTests: XCTestCase {
func testEncodingJWT() {
let payload = ["name": "Kyle"] as Payload
let jwt = JWT.encode(claims: payload, algorithm: .hs256("secret".data(using: .utf8)!))

let expected = [
// { "alg": "HS256", "typ": "JWT" }
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiS3lsZSJ9.zxm7xcp1eZtZhp4t-nlw09ATQnnFKIiSN83uG8u6cAg",

// { "typ": "JWT", "alg": "HS256" }
"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiS3lsZSJ9.4tCpoxfyfjbUyLjm9_zu-r52Vxn6bFq9kp6Rt9xMs4A",
"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiS3lsZSJ9.4tCpoxfyfjbUyLjm9_zu-r52Vxn6bFq9kp6Rt9xMs4A"
]

XCTAssertTrue(expected.contains(jwt))
}

func testEncodingWithBuilder() {
let algorithm = Algorithm.hs256("secret".data(using: .utf8)!)
let jwt = JWT.encode(algorithm) { builder in
builder.issuer = "fuller.li"
}

XCTAssertEqual(jwt, "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJmdWxsZXIubGkifQ.d7B7PAQcz1E6oNhrlxmHxHXHgg39_k7X7wWeahl8kSQ")

let expected = [
// { "alg": "HS256", "typ": "JWT" }
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJmdWxsZXIubGkifQ.d7B7PAQcz1E6oNhrlxmHxHXHgg39_k7X7wWeahl8kSQ",
// { "typ": "JWT", "alg": "HS256" }
"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJmdWxsZXIubGkifQ.x5Fdll-kZBImOPtpT1fZH_8hDW01Ax3pbZx_EiljoLk"
]

XCTAssertTrue(expected.contains(jwt))
}

func testEncodingClaimsWithHeaders() {
let algorithm = Algorithm.hs256("secret".data(using: .utf8)!)
let jwt = JWT.encode(claims: ClaimSet(), algorithm: algorithm, headers: ["kid": "x"])

XCTAssertEqual(jwt, "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IngifQ.e30.ddEotxYYMMdat5HPgYFQnkHRdPXsxPG71ooyhIUoqGA")

let expected = [
// { "alg": "HS256", "typ": "JWT", "kid": "x" }
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IngifQ.e30.ddEotxYYMMdat5HPgYFQnkHRdPXsxPG71ooyhIUoqGA",
// { "alg": "HS256", "kid": "x", "typ": "JWT" }
"eyJhbGciOiJIUzI1NiIsImtpZCI6IngiLCJ0eXAiOiJKV1QifQ.e30.xiT6fWe5dWGeuq8zFb0je_14Maa_9mHbVPSyJhUIJ54",
// { "typ": "JWT", "alg": "HS256", "kid": "x" }
"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6IngifQ.e30.5t6a61tpSXFo5QBHYCnKAz2mTHrW9kaQ9n_b7e-jWw0",
// { "typ": "JWT", "kid": "x", "alg": "HS256" }
"eyJ0eXAiOiJKV1QiLCJraWQiOiJ4IiwiYWxnIjoiSFMyNTYifQ.e30.DG5nmV2CVH6mV_iEm0xXZvL0DUJ22ek2xy6fNi_pGLc",
// { "kid": "x", "typ": "JWT", "alg": "HS256" }
"eyJraWQiOiJ4IiwidHlwIjoiSldUIiwiYWxnIjoiSFMyNTYifQ.e30.h5ZvlqECBIvu9uocR5_5uF3wnhga8vTruvXpzaHpRdA",
// { "kid": "x", "alg": "HS256", "typ": "JWT" }
"eyJraWQiOiJ4IiwiYWxnIjoiSFMyNTYiLCJ0eXAiOiJKV1QifQ.e30.5KqN7N5a7Cfbe2eKN41FJIfgMjcdSZ7Nt16xqlyOeMo"
]

XCTAssertTrue(expected.contains(jwt))
}
}
Loading