Swiftpack.co - vapor/jwt-kit as Swift Package

Swiftpack.co is a collection of thousands of indexed Swift packages. Search packages.
See all packages published by vapor.
vapor/jwt-kit 4.13.0
๐Ÿ”‘ JSON Web Token signing and verification (HMAC, RSA, ECDSA) using BoringSSL.
โญ๏ธ 124
๐Ÿ•“ 10 weeks ago
iOS macOS watchOS tvOS linux macOS iOS
.package(url: "https://github.com/vapor/jwt-kit.git", from: "4.13.0")

JWTKit Documentation Team Chat MIT License CI Swift 5.6

๐Ÿ”‘ JSON Web Token signing and verification (HMAC, RSA, ECDSA, EdDSA) using SwiftCrypto and BoringSSL.

Major Releases

The table below shows a list of JWTKit major releases alongside their compatible Swift versions.

Version Swift SPM
4.0 5.6+ from: "4.0.0"

Use the SPM string to easily include the dependendency in your Package.swift file.

.package(url: "https://github.com/vapor/jwt-kit.git", from: "4.0.0")

Note: Prior to version 4.0, this package was part of vapor/jwt.

Supported Platforms

JWTKit supports all platforms supported by Swift 5.6 and later, with the exception of Windows.


JWTKit provides APIs for signing and verifying JSON Web Tokens, as specified by RFC 7519. The following features are supported:

  • Parsing
  • Signature verification
  • Payload signing
  • Serialization
  • Claim validation (aud, exp, jti, iss, iat, nbf, sub, and custom claims)
  • JSON Web Keys (JWK, JWKS)

The following algorithms, as defined in RFC 7518 ยง 3 and RFC 8037 ยง 3, are supported for both signing and verification:

  • HS256, HS384, HS512 (HMAC with SHA-2)
  • RS256, RS384, RS512 (RSA with SHA-2)
  • ES256, ES384, ES512 (ECDSA with SHA-2)
  • EdDSA
  • none (unsigned)

For those algorithms which specify a curve type (crv), the following curves, as defined in RFC 7518 ยง 6 and RFC 8037 ยง 3, are supported:

  • P-256 (ES256 algorithm only)
  • P-384 (ES384 algorithm only)
  • P-521 (ES512 algorithm only)
  • Ed25519 (EdDSA algorithm only)

This package includes a vendored internal-only copy of BoringSSL, used for certain cryptographic operations not currently available via SwiftCrypto.

Note: The P-521 elliptic curve used with the ES512 signing algorithm is often assumed to be a typo, but confusingly, it is not.


The vapor/jwt package provides first-class integration with Vapor and is recommended for all Vapor projects which want to use JWTKit.

Getting Started

A JWTSigners object is used to load signing keys and keysets, and to sign and verify tokens:

import JWTKit

// Signs and verifies JWTs
let signers = JWTSigners()

The JWTSigner class encapsulates a signature algorithm and an appropriate signing key. To use a signer, register it with the JWTSigners object:

// Registers a HS256 (HMAC-SHA-256) signer.
signers.use(.hs256(key: "secret"))

This example uses the very secure key "secret".


Let's try to verify the following example JWT:

let exampleJWT = """

You can inspect the contents of this token by visiting jwt.io and pasting the token in the debugger. Set the key in the "Verify Signature" section to secret.

To verify a token, the format of the payload must be known. This is accomplished by defining a type conforming to the JWTPayload protocol. Each property of the payload type corresponds to a claim in the token. JWTKit provides predefined types for all of the claims specified by RFC 7519, as well as some convenience types for working with custom claims. For the example token, the payload looks like this:

struct ExamplePayload: JWTPayload {
    var sub: SubjectClaim
    var exp: ExpirationClaim
    var admin: BoolClaim

    func verify(using signer: JWTSigner) throws {
        try self.exp.verifyNotExpired()

Using this payload, the JWTSigners object can process and verify the example JWT, returning its payload on success:

// Parses the JWT, verifies its signature, and decodes its content.
let payload = try signers.verify(exampleJWT, as: ExamplePayload.self)

If all works correctly, this code will print something like this:

    sub: SubjectClaim(value: "vapor"),
    exp: ExpirationClaim(value: 4001-01-01 00:00:00 +0000),
    admin: BoolClaim(value: true)

Note: The admin property of the example payload did not have to use the BoolClaim type; a simple Bool would have worked as well. The BoolClaim type is provided by JWTKit for convenience in working with the many JWT implementations which encode boolean values as JSON strings (e.g. "true" and "false") rather than using JSON's true and false keywords.


We can also generate JWTs, also known as signing. To demonstrate this, let's use the TestPayload from the previous section.

// Create a new instance of our JWTPayload
let payload = ExamplePayload(
    subject: "vapor",
    expiration: .init(value: .distantFuture),
    isAdmin: true

Then, pass the payload to JWTSigners.sign.

// Sign the payload, returning a JWT.
let jwt = try signers.sign(payload)

You should see a JWT printed. This can be fed back into the verify method to access the payload.


A JSON Web Key (JWK) is a JavaScript Object Notation (JSON) data structure that represents a cryptographic key, defined in RFC7517. These are commonly used to supply clients with keys for verifying JWTs. For example, Apple hosts their Sign in with Apple JWKS at the URL https://appleid.apple.com/auth/keys.

You can add this JSON Web Key Set (JWKS) to your JWTSigners:

import Foundation
import JWTKit

// Download the JWKS.
// This could be done asynchronously if needed.
let jwksData = try String(
    contentsOf: URL(string: "https://appleid.apple.com/auth/keys")!

// Create signers and add JWKS.
let signers = JWTSigners()
try signers.use(jwksJSON: jwksData)

You can now pass JWTs from Apple to the verify method. The key identifier (kid) in the JWT header will be used to automatically select the correct key for verification. A JWKS may contain any of the key types supported by JWTKit.


HMAC is the simplest JWT signing algorithm. It uses a single key that can both sign and verify tokens. The key can be any length.

  • hs256: HMAC with SHA-256
  • hs384: HMAC with SHA-384
  • hs512: HMAC with SHA-512
// Add HMAC with SHA-256 signer.
signers.use(.hs256(key: "secret"))


RSA is the most commonly used JWT signing algorithm. It supports distinct public and private keys. This means that a public key can be distributed for verifying JWTs are authentic while the private key that generates them is kept secret.

To create an RSA signer, first initialize an RSAKey. This can be done by passing in the components:

// Initialize an RSA key with components.
let key = RSAKey(
    modulus: "...",
    exponent: "...",
    // Only included in private keys.
    privateExponent: "..."

You can also choose to load a PEM file:

let rsaPublicKey = """
-----END PUBLIC KEY-----

// Initialize an RSA key with public pem.
let key = RSAKey.public(pem: rsaPublicKey)

Use .private for loading private RSA pem keys. These start with:


Use .certificate for loading X.509 certificates. These start with:


Once you have the RSAKey, you can use it to create an RSA signer:

  • rs256: RSA with SHA-256
  • rs384: RSA with SHA-384
  • rs512: RSA with SHA-512
// Add RSA with SHA-256 signer.
try signers.use(.rs256(key: .public(pem: rsaPublicKey)))

Important: RSA, despite still being the common algorithm in use, is no longer recommended for new applications. If possible, use EdDSA or ECDSA instead.


ECDSA is a more modern algorithm that is similar to RSA. It is considered to be more secure for a given key length than RSA. Infosec Insights' June 2020 blog post "ECDSA vs RSA: Everything You Need to Know" provides a detailed discussion on the differences between the two.

IMPORTANT: Cryptography is a complex topic, and the decision of algorithm can directly impact the integrity, security, and privacy of your data. This README does not attempt to offer a meaningful discussion of these concerns; the package authors recommend doing your own research before making a final decision.

Like RSA, you can load ECDSA keys using PEM files:

let ecdsaPublicKey = """
-----END PUBLIC KEY-----

// Initialize an ECDSA key with public pem.
let key = ECDSAKey.public(pem: ecdsaPublicKey)

Use .private for loading private ECDSA pem keys. These start with:


Once you have the ECDSAKey, you can use it to create an ECDSA signer:

  • es256: ECDSA with SHA-256 and P-256
  • es384: ECDSA with SHA-384 and P-384
  • es512: ECDSA with SHA-512 and P-521
// Add ECDSA with SHA-256 signer.
try signers.use(.es256(key: .public(pem: ecdsaPublicKey)))


JWTKit includes several helpers for implementing the "standard" JWT claims defined by RFC ยง 4.1:

Claim Type Verify Method
aud AudienceClaim verifyIntendedAudience(includes:)
exp ExpirationClaim verifyNotExpired(currentDate:)
jti IDClaim n/a
iat IssuedAtClaim n/a
iss IssuerClaim n/a
nbf NotBeforeClaim verifyNotBefore(currentDate:)
sub SubjectClaim n/a

Whenever possible, all of a payload's claims should be verified in the verify(using:) method; those which do not have verification methods of their own may be verified manually.

Additional helpers are provided for common types of claims not defined by the RFC:

  • BoolClaim: May be used for any claim whose value is a boolean flag. Will recognize both boolean JSON values and the strings "true" and "false".
  • GoogleHostedDomainClaim: For use with the GoogleIdentityToken vendor token type.
  • JWTMultiValueClaim: A protocol for claims, such as AudienceClaim which can optionally be encoded as an array with multiple values.
  • JWTUnixEpochClaim: A protocol for claims, such as ExpirationClaim and IssuedAtClaim, whose value is a count of seconds since the UNIX epoch (midnight of January 1, 1970).
  • LocaleClaim: A claim whose value is a BCP 47 language tag. Also used by GoogleIdentityToken.

This package was originally authored by the wonderful @siemensikkema.


Stars: 124
Last commit: 5 weeks ago
jonrohan Something's broken? Yell at me @ptrpavlik. Praise and feedback (and money) is also welcome.


Related Packages

Release Notes

4.13.0 - Add customizable JSON encoders and decoders
10 weeks ago

Add new, fully source-compatible APIs to JWTSigners and JWTSigner which allow specifying custom JSON encoders and decoders. Also provides the JWTJSONEncoder and JWTJSONDecoder protocols, which allow using alternative JSON implementations.

Custom coders specified for a single JWTSigner affect token parsing and signing performed only by that signer. Custom coders specified on a JWTSigners object will become the default coders for all signers added to that object, unless a given signer already specifies its own custom coders.

The default encoding and decoding implementation provided for JWTUnixEpochClaim (of which ExpirationClaim (exp), IssuedAtClaim (iat), and NotBeforeClaim (nbf) are examples) has been adjusted to encode and decode its Date value directly, rather than performing the explicit conversion to and from a Double. This allows these claims to take advantage of the dateEncodingStrategy and dateDecodingStrategy specified on custom JSON coders. (It also gives a bit of the lie to the name JWTUnixEpochClaim, but it's public API, so I left it alone.)

The default coders in use remain the same: An encoder and decoder which use the .secondsSince1970 date encoding/decoding strategy. As such, neither the new support nor the change to Date-based claims affects how tokens are signed or verified unless custom coders with different strategies are specified (that being, after all, the original need which inspired these changes).

Finally, an .integerSecondsSince1970 date encoding and decoding strategy has been added to the public API for the benefit of interoperation with JWT implementations - such as that used by GitHub - which require the aforementioned date-based claims to specify values as an integer number of seconds. (As GitHub proves, while this is in violation of the definition of NumericDate given by RFC 7519 ยง 2, which explicitly permits floating-point values, it nonetheless appears in the wild.)

This is a semver-minor release, as it adds new public API (although it has been careful to fully retain source compatibility, at the cost of a goodly amount of silly-looking repetition in the implementation - please, do not ask me if I know what default parameter values are! ๐Ÿ˜‚).

Swiftpack is being maintained by Petr Pavlik | @ptrpavlik | @swiftpackco | API | Analytics