SwiftJWT Documentation

repository·master·Indexed 20 days ago

https://github.com/kitura/swift-jwt

A Swift implementation of JSON Web Tokens (RFC 7519) for securely transmitting information via digitally signed tokens. It provides tools for signing and verifying JWTs using JWTSigner and JWTVerifier, supporting algorithms such as RS, HS, ES, and PS. The library includes JWTEncoder and JWTDecoder for encoding and decoding, a Claims protocol for custom data, and built-in validation for temporal claims like exp, nbf, and iat.

Tokens
2.4K
Snippets
13
Records
14
Agent score
20%

What's inside SwiftJWT

  1. Use JWTSigner and JWTVerifier instead of Algorithm

    master

    The Algorithm enum has been replaced by JWTSigner (for signing) and JWTVerifier (for verifying). This removes the need to manually specify the key type (e.g., .privateKey or .publicKey) as the specific signer/verifier methods now handle this context.

    let privateKey = "<PrivateKey>".data(using: .utf8)!
    let publicKey = "<PublicKey>".data(using: .utf8)!
    
    // Swift-JWT 3.0+
    let signer = JWTSigner.rs256(privateKey: privateKey)
    let verifier = JWTVerifier.rs256(publicKey: publicKey)
  2. Validate Claims in Swift-JWT 3.0+

    master

    The validateClaims() method now only automatically validates time-based claims: iat (issued at), exp (expiration), and nbf (not before). For other claims like iss (issuer) or aud (audience), you must perform manual validation against the properties of the decoded JWT.

    // Swift-JWT 3.0+
    // Automatically checks iat, exp, and nbf
    let validationResult = jwt.validateClaims()
    
    // Manually check issuer and audience
    let isValid = jwt.iss == "issuer" && jwt.aud == "clientID"
  3. Install SwiftJWT via Swift Package Manager or CocoaPods

    master

    To use SwiftJWT in your Swift project, you can use either Swift Package Manager or CocoaPods.

    Swift Package Manager

    Add the package to your Package.swift dependencies, replacing x.x.x with the latest release version:

    .package(url: "https://github.com/Kitura/Swift-JWT.git", from: "x.x.x")

    Then, add SwiftJWT to your target's dependencies:

    .target(name: "example", dependencies: ["SwiftJWT"]),

    CocoaPods

    Add SwiftJWT to your Podfile:

    pod 'SwiftJWT'
    // Swift Package Manager example
    .package(url: "https://github.com/Kitura/Swift-JWT.git", from: "x.x.x")
    .target(name: "example", dependencies: ["SwiftJWT"])
    
    // CocoaPods example
    pod 'SwiftJWT'
  4. Define custom Claims using the Claims protocol

    master

    In Swift-JWT 3.0+, Claims is a protocol rather than a fixed struct. To use custom data in your JWT, define a struct that conforms to Claims. Alternatively, you can use the built-in ClaimsStandardJWT for standard claims.

    // Swift-JWT 3.0+, User defined claims
    struct MyClaims: Claims {
        let sub: String
        let iss: String
    }
    let myClaims = MyClaims(sub: "user123", iss: "Kitura")
    
    // Swift-JWT 3.0+, Using Standard Claims
    let standardClaims = ClaimsStandardJWT(iss: "Kitura")
  5. Sign and Verify JWTs in Swift-JWT 3.0+

    master

    The API for signing and verifying has been updated:

    1. Signing: jwt.sign(using:) now takes a JWTSigner and returns a non-optional String. To encode a JWT without a signature, use .none.
    2. Verifying: JWT<Claims>.verify(jwtString:using:) is used to verify a string. Note that verify no longer throws.
    3. Decoding: Use the jwtString: initializer instead of the old decode() method.
    // Signing
    let signedJWT: String = try jwt.sign(using: JWTSigner.rs256(privateKey: key))
    
    // Encoding without signature
    let encodedJWT = try jwt.sign(using: .none)
    
    // Decoding
    let decodedJWT = try JWT<MyClaims>(jwtString: encodedJWT)
    
    // Verifying
    let verified = JWT<MyClaims>.verify(signedJWT, using: JWTVerifier.rs256(publicKey: key))
  6. Migrate Header usage to Swift-JWT 3.0+

    master

    In Swift-JWT 3.0+, the Header struct conforms to Codable and uses fixed fields instead of a dictionary. You now initialize it using named arguments and access fields directly as properties rather than using string keys.

    // Swift-JWT 3.0+
    let header = Header(typ: "JWT", kid: "KeyID")
    let keyID = header.kid
  7. Sign a JWT using JWTSigner

    master

    To sign a JWT, you need a JWTSigner initialized with an appropriate algorithm and a private key. The sign method on a JWT instance will then generate the signed string.

    1. Initialize a signer (e.g., using rs256 with a private key).
    2. Call .sign(using:) on your JWT object.

    Note: The sign function automatically sets the alg (algorithm) field in the JWT header.

    Supported algorithms include RS256, RS384, RS512, HS256, HS384, HS512, ES256, ES384, ES512, PS256, PS384, PS512, and none.

    // 1. Initialize signer
    let jwtSigner = JWTSigner.rs256(privateKey: privateKey)
    
    // 2. Sign the JWT
    let signedJWT = try myJWT.sign(using: jwtSigner)
    // signedJWT is a String: <encoded header>.<encoded claims>.<signature>
  8. Use JWTEncoder and JWTDecoder for encoding/decoding

    master

    JWTEncoder and JWTDecoder provide an API similar to JSONEncoder and JSONDecoder for working with JWT strings.

    // Encoding
    let jwtEncoder = JWTEncoder(jwtSigner: jwtSigner)
    let jwtString = try jwtEncoder.encodeToString(myJWT)
    
    // Decoding
    let jwtDecoder = JWTDecoder(jwtVerifier: jwtVerifier)
    let jwt = try jwtDecoder.decode(JWT<MyClaims>.self, fromString: jwtString)

    Because they conform to BodyEncoder and BodyDecoder protocols, they can be used as custom coders in Kitura routes for application/jwt media types.

    let jwtEncoder = JWTEncoder(jwtSigner: jwtSigner)
    let jwtString = try jwtEncoder.encodeToString(myJWT)
    
    let jwtDecoder = JWTDecoder(jwtVerifier: jwtVerifier)
    let jwt = try jwtDecoder.decode(JWT<MyClaims>.self, fromString: jwtString)
  9. Verify a JWT using JWTVerifier

    master

    To verify the integrity of a signed JWT string, use the JWTVerifier struct and the static verify method.

    1. Initialize a JWTVerifier with the corresponding algorithm and public key.
    2. Call JWT<YourClaimsType>.verify(jwtString, using: verifier).

    This returns a Bool indicating whether the signature is valid.

    // 1. Initialize verifier
    let jwtVerifier = JWTVerifier.rs256(publicKey: publicKey)
    
    // 2. Verify the string
    let verified = JWT<MyClaims>.verify(signedJWT, using: jwtVerifier)
    // verified is a Bool
  10. Decode a JWT string into a JWT object

    master

    You can initialize a JWT struct directly from a Base64Url encoded JWT string. If you provide a JWTVerifier, the library will automatically verify the signature before completing the initialization.

    let newJWT = try JWT<MyClaims>(jwtString: signedJWT, verifier: jwtVerifier)
    let newJWT = try JWT<MyClaims>(jwtString: signedJWT, verifier: jwtVerifier)
  11. Validate standard JWT date claims

    master

    After verifying a signature, you should validate the standard temporal claims to ensure the token is still valid. The validateClaims method checks the following if present in your Claims object:

    • exp (expiration date)
    • nbf (not before date)
    • iat (issued at date)

    You can provide a leeway (in seconds) to account for clock skew between the issuer and the verifier.

    Returns a ValidateClaimsResult which is .success if all checks pass.

    let validationResult = verified.validateClaims(leeway: 10)
    if validationResult != .success {
        print("Claims validation failed: ", validationResult)
    }