• Stars
    star
    180
  • Rank 213,097 (Top 5 %)
  • Language
    Swift
  • License
    MIT License
  • Created almost 5 years ago
  • Updated 3 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

๐Ÿ”‘ JSON Web Token (JWT) signing and verification (HMAC, ECDSA, EdDSA, RSA, PSS) with support for JWS and JWK

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.

Overview

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.

Vapor

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".

Verifying

Let's try to verify the following example JWT:

let exampleJWT = """
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ2YXBvciIsImV4cCI6NjQwOTIyMTEyMDAsImFkbWluIjp0cnVlfQ.lS5lpwfRNSZDvpGQk6x5JI1g40gkYCOWqbc3J_ghowo
"""

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)
print(payload)

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

TestPayload(
    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.

Signing

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)
print(jwt)

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

JWK

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

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

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 = """
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC0cOtPjzABybjzm3fCg1aCYwnx
PmjXpbCkecAWLj/CcDWEcuTZkYDiSG0zgglbbbhcV0vJQDWSv60tnlA3cjSYutAv
7FPo5Cq8FkvrdDzeacwRSxYuIq1LtYnd6I30qNaNthntjvbqyMmBulJ1mzLI+Xg/
aX4rbSL49Z3dAQn8vQIDAQAB
-----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:

-----BEGIN RSA PRIVATE KEY-----

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

-----BEGIN CERTIFICATE-----

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

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 = """
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE2adMrdG7aUfZH57aeKFFM01dPnkx
C18ScRb4Z6poMBgJtYlVtd9ly63URv57ZW0Ncs1LiZB7WATb3svu+1c7HQ==
-----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:

-----BEGIN PRIVATE KEY-----

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)))

Claims

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.

More Repositories

1

vapor

๐Ÿ’ง A server-side Swift HTTP web framework.
Swift
24,188
star
2

fluent

Vapor ORM (queries, models, and relations) for NoSQL and SQL databases
Swift
1,308
star
3

redis

Vapor provider for RediStack
Swift
458
star
4

console-kit

๐Ÿ’ป APIs for creating interactive CLI tools.
Swift
456
star
5

leaf

๐Ÿƒ An expressive, performant, and extensible templating language built for Swift.
Swift
432
star
6

postgres-nio

๐Ÿ˜ Non-blocking, event-driven Swift client for PostgreSQL.
Swift
325
star
7

jwt

Vapor JWT provider
Swift
317
star
8

docs

๐Ÿ“– Documentation markdown for all Vapor packages.
Swift
316
star
9

toolbox

Simplifies common command line tasks when using Vapor
Swift
283
star
10

websocket-kit

WebSocket client library built on SwiftNIO
Swift
272
star
11

sql-kit

*๏ธโƒฃ Build SQL queries in Swift. Extensible, protocol-based design that supports DQL, DML, and DDL.
Swift
239
star
12

http

๐Ÿš€ Non-blocking, event-driven HTTP built on Swift NIO.
Swift
238
star
13

mysql-kit

๐Ÿฌ Pure Swift MySQL client built on non-blocking, event-driven sockets.
Swift
222
star
14

fluent-kit

Swift ORM (queries, models, and relations) for NoSQL and SQL databases
Swift
206
star
15

postgres-kit

๐Ÿ˜ Non-blocking, event-driven Swift client for PostgreSQL.
Swift
187
star
16

queues

A queue system for Vapor.
Swift
163
star
17

fluent-postgres-driver

๐Ÿ˜ PostgreSQL driver for Fluent.
Swift
145
star
18

api-template

๐Ÿ’ง A starting point for Vapor APIs.
Swift
135
star
19

open-crypto

๐Ÿ”‘ Hashing (BCrypt, SHA2, HMAC), encryption (AES), public-key (RSA), and random data generation.
Swift
134
star
20

multipart-kit

๐Ÿž Parses and serializes multipart-encoded data with Codable support.
Swift
132
star
21

routing-kit

๐Ÿš High-performance trie-node router.
Swift
122
star
22

apns

Helpful extensions and abstractions for using APNSwift
Swift
115
star
23

mysql-nio

๐Ÿฌ Non-blocking, event-driven Swift client for MySQL.
Swift
88
star
24

service

๐Ÿ“ฆ Dependency injection / inversion of control framework.
Swift
85
star
25

core

๐ŸŒŽ Utility package containing tools for byte manipulation, Codable, OS APIs, and debugging.
Swift
80
star
26

fluent-mysql-driver

๐Ÿ–‹๐Ÿฌ Swift ORM (queries, models, relations, etc) built on MySQL.
Swift
76
star
27

async-kit

Sugary extensions for the SwiftNIO library
Swift
71
star
28

template

Used by Vapor Toolboxโ€™s new project command
Swift
70
star
29

fluent-sqlite-driver

Fluent driver for SQLite
Swift
67
star
30

sqlite-kit

Non-blocking SQLite client library with SQL builder built on SwiftNIO
Swift
58
star
31

sqlite-nio

Non-blocking wrapper for libsqlite3-dev using SwiftNIO
C
58
star
32

validation

โœ… Extensible data validation library (name, email, etc)
Swift
56
star
33

auth

๐Ÿ‘ค Authentication and Authorization framework for Fluent.
Swift
53
star
34

leaf-kit

๐Ÿƒ An expressive, performant, and extensible templating language built for Swift.
Swift
47
star
35

template-kit

๐Ÿ“„ Easy-to-use foundation for building powerful templating languages in Swift.
Swift
45
star
36

website

Vapor's website running on Swift
Swift
45
star
37

docs-cn

๐Ÿ‡จ๐Ÿ‡ณ Chinese translation of Vapor's documentation markdown.
HTML
43
star
38

web-template

A starting point for web applications
Swift
41
star
39

url-encoded-form

๐Ÿ“ Parse and serialize url-encoded form data with Codable support.
Swift
41
star
40

database-kit

๐Ÿ—„ Core services for creating database integrations.
Swift
40
star
41

auth-template

A starting point for Vapor applications using the auth provider.
Swift
35
star
42

university

Web application, iOS app, and API providing access to tutorials for the Vapor web framework.
Swift
24
star
43

fluent-mongo-driver

MongoDB support for Fluent built on MongoKittten.
Swift
24
star
44

queues-redis-driver

A Redis implementation for https://github.com/vapor/queues
Swift
22
star
45

design

Contains the reference designs and build pipeline to generate all design files for Vapor's sites
Swift
22
star
46

email

A common API for Vapor to integrate with different email providers
Swift
20
star
47

codable-kit

Conveniences for working with Swift's Codable protocols.
Swift
19
star
48

kafka

Swift Apacha Kafka (real-time data pipelines and streaming apps)
Swift
19
star
49

apt

Manage Vapor's Swift APT repository
Shell
17
star
50

blog

The Vapor Blog
Swift
16
star
51

penny-bot

The code that runs Penny ๐Ÿค–
Swift
15
star
52

template-bare

A barebones template ready for use
Swift
12
star
53

docker

Swift
12
star
54

api-docs

Scripts and assets for Vapor's API documentation site at https://api.vapor.codes
Swift
11
star
55

redis-kit

Helpful extensions and abstractions for using RediStack
Swift
8
star
56

swift-getting-started-web-server

The source code for the Getting Started Guide on Vapor on swift.org
Swift
7
star
57

homebrew-tap

Homebrew Taps
Ruby
7
star
58

template-fluent-postgres

A template ready for use configured with Fluent and PostgreSQL
Swift
6
star
59

release-bot

Webhook-based GitHub bot that automatically tags new releases and posts to Discord when you merge PRs
Swift
6
star
60

ci

Support files and configurations for Vapor's CI
Swift
5
star
61

bot-github

A github bot to do things like interact with CI for the Vapor organization
Swift
5
star
62

template-fluent-postgres-leaf

A template ready for use configured with Leaf, Fluent and PostgreSQL
Swift
4
star
63

swiftly-action

Simple one-step access to the Swiftly toolchain manager from GitHub Actions workflows
3
star
64

swift-codecov-action

A GitHub Action which performs Codecov.io uploads with additional support for Swift projects
Swift
3
star
65

template-fluent-mysql

A template ready for use configured with Fluent and MySQL
Swift
2
star
66

docs-de

Deutsche รœbersetzung der Vapor-Dokumentation
HTML
1
star