VaporJWT is a library for JSON Web Tokens (JWT) designed with the following goals in mind:
- clean API
- native to Vapor
- many features
- highly extensible
A JWT (pronounced "jot") provides a secure way to grant access to a resource based on certain constraints. The constraints are expressed as unencrypted claims and can be used to constrain access to a certain time or audience among other things. Tokens are signed to protect against tampering.
The unencrypted nature of the claims makes it possible for the validity of the token to be evaluated on the client without having access to the private key or having to access the server. When the server receives a JWT (e.g. in the bearer Authorization header), it can quickly reject any invalid tokens without having to do a database lookup.
The structure of a JWT is base64Encoded(headerJSON).base64Encoded(payloadJSON).signature
.
Add the following package to Package.swift
.Package(url:"https://github.com/siemensikkema/vapor-jwt.git", majorVersion: 0, minor: 6)
For detailed info on how to use this library see the tests and, if you run macOS, the included playground.
To run the playground:
- run
vapor xcode
- open the workspace 'Playground/VaporJWT.xcworkspace' in Xcode
- select the playground
- build the 'VaporJWT' scheme
Import the library:
import VaporJWT
Create an signed token that expires 1 minute from now.
let jwt = try JWT(payload: Node(ExpirationTimeClaim(Date() + 60)),
signer: HS256(key: "secret"))
let token = try jwt.createToken()
VaporJWT creates default headers ("typ" and "alg") when none are provided. VaporJWT provides convenient ways to configure a JWT with custom headers and claims. For full control you can set the headers and payload as Node
s.
let jwt = try JWT(headers: Node(["my": .string("header")]),
payload: Node(["user_id": .number(.int(42))]),
signer: Unsigned())
let jwt3 = try JWT(token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhIjoiYiJ9.jiMyrsmD8AoHWeQgmxZ5yq8z0lXS67/QGs52AzC8Ru8=")
let isValid = try jwt3.verifySignatureWith(HS256(key: "secret"))
VaporJWT supports HMAC, ECDSA, and RSA signing. The available signers are:
- HS256
- HS284
- HS512
- ES256
- ES384
- ES512
- RS256
- RS384
- RS512
The HMAC (HS*) signers take the same private key for both signing and verifying. The ECDSA and RSA (ES*/RS*) signers on the other hand take a private key for signing and a matching public key for verifying.
Create a new key pair for ES256:
openssl ecparam -name prime256v1 -genkey -out private.pem
(For the ES384 signer substitute prime256v1
with secp384r1
and for ES512 use secp521r1
.)
Extract the private key:
openssl ec -in private.pem -outform der -out private.der
openssl base64 -in private.der -out /dev/stdout
Extract the public key:
openssl ec -in private.pem -outform der -pubout -out public.der
openssl base64 -in public.der -out /dev/stdout
To generate a 4096 bit private/public key pair for RSA use the following command:
openssl genrsa -out private.pem 4096
Extract the private key:
openssl rsa -in private.pem -outform der -out private.der
openssl base64 -in private.der -out /dev/stdout
Extract the public key:
openssl rsa -in private.pem -outform der -pubout -out public.der
openssl base64 -in public.der -out /dev/stdout
Besides the included signers it is possible to create your own by adhering to the Signer
protocol:
public protocol Signer {
var name: String { get }
func sign(_ message: Bytes) throws -> Bytes
func verifySignature(_ signature: Bytes, message: Bytes) throws -> Bool
}
By default VaporJWT uses Base64 encoding. A Base64URL encoder/decoder is also available and can be used like so:
let jwt = try JWT(payload: [],
encoding: Base64URLEncoding(),
signer: Unsigned())
Any custom encoding that adheres to the Encoding
protocol can be used as well.
public protocol Encoding {
func decode(_ : String) throws -> Bytes
func encode(_ : Bytes) throws -> String
}
Existing libraries were pretty great already but I wanted a more extensible library that felt native to Vapor. I also wanted better encryption support, with ES256 in particular because it is needed by for Apple's new token based push notifications, see VaporAPNS.
See the project board.
Yes please! Issues and pull requests are more than welcome.
- https://github.com/kylef/JSONWebToken.swift
- http://davidederosa.com/basic-blockchain-programming/elliptic-curve-keys/
- http://davidederosa.com/basic-blockchain-programming/elliptic-curve-digital-signatures/
- https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25
- https://kjur.github.io/jsrsasign/sample-ecdsa.html