Swift library for decoding, validating, signing and verifying JWT
- Verify and sign :
- HMAC HS256HS384HS512
- RSASSA-PKCS1-v1_5 RS256RS384RS384
 
- HMAC 
- Validate (optionally) all registered claims :
- Issuer iss
- Subject sub
- Audience aud
- Expiration Time exp
- Not Before nbf
- Issued At iat
- JWT ID jti
 
- Issuer 
- No external dependencies : CommonCrypto and Security framework are used for signing and verifying
- Extensible : add your own claim validator and sign operations
import JSONWebToken
let rawJWT : String
let jwt : JSONWebToken = try JSONWebToken(string : rawJWT)
//create the validator by combining other validators with the & or | operator
let validator = RegisteredClaimValidator.expiration & 
				RegisteredClaimValidator.notBefore.optional &
				HMACSignature(secret: "secret".dataUsingEncoding(NSUTF8StringEncoding)!, hashFunction: .SHA256)
/*
- not expired
- can be used now (optional : a jwt without nbf will be valid)
- signed with HS256 and the key "secret"
*/
let validationResult = validator.validateToken(jwt)
guard case ValidationResult.Success = validationResult else { return }
//use the token and access the payload
let issuer : String? = jwt.payload.issuer
let customClaim = jwt.payload["customClaim"] as? Stringimport JSONWebToken
//build the payload
var payload = JSONWebToken.Payload()
payload.issuer = "http://kreactive.com"
payload.subject = "antoine"            
payload.audience = ["com.kreactive.app"]
payload.expiration = NSDate().dateByAddingTimeInterval(300)
payload.notBefore = NSDate()
payload.issuedAt = NSDate()
payload.jwtIdentifier = NSUUID().UUIDString
payload["customClaim"] = "customClaim"
//use HS256 to sign the token
let signer = HMACSignature(secret: "secret".dataUsingEncoding(NSUTF8StringEncoding)!, hashFunction: .SHA256) 
//build the token, signer is optional
let jwt = try JSONWebToken(payload : payload, signer : signer)
let rawJWT : String = jwt.rawStringKeys are represented by the RSAKey struct, wrapping a SecKeyRef.
The preferred way of importing public keys is to use a DER-encoded X.509 certificate (.cer), and for private keys a PKCS#12 (.p12) identity.
It's also possible to import raw representation of keys (X509, public pem, modulus/exponent ...) by using a keychain item import side effect.
let certificateData : NSData = //DER-encoded X.509 certificate
let publicKey : RSAKey = try RSAKey(certificateData : certificateData)let p12Data : NSData //PKCS #12–formatted identity data
let identity : (publicKey : RSAKey, privateKey : RSAKey) = try RSAKey.keysFromPkcs12Identity(p12Data, passphrase : "pass")let keyData : NSData
//import key into the keychain
let key : RSAKey = try RSAKey.registerOrUpdateKey(keyData, tag : "keyTag")let modulusData : NSData
let exponentData : NSData
//import key into the keychain
let key : RSAKey = try RSAKey.registerOrUpdateKey(modulus : modulusData, exponent : exponentData, tag : "keyTag")Retrieve or delete key from the keychain :
//get registered key
let key : RSAKey? = RSAKey.registeredKeyWithTag("keyTag")
//remove
RSAKey.removeKeyWithTag("keyTag")A large part of the raw key import code is copied from the Heimdall library.
Use RSAPKCS1Verifier as validator to verify token signature :
let jwt : JSONWebToken
let publicKey : RSAKey
let validator = RegisteredClaimValidator.expiration & 
				RegisteredClaimValidator.notBefore.optional &
				RSAPKCS1Verifier(key : publicKey, hashFunction: .SHA256)
				
let validationResult = validator.validateToken(jwt)
...Use RSAPKCS1Signer to generate signed token:
let payload : JSONWebToken.Payload
let privateKey : RSAKey
let signer = RSAPKCS1Signer(hashFunction: .SHA256, key: privateKey)	
let jwt = try JSONWebToken(payload : payload, signer : signer)
let rawJWT : String = jwt.rawString
...Validators (signature and claims) implement the protocol JSONWebTokenValidatorType
public protocol JSONWebTokenValidatorType {
    func validateToken(token : JSONWebToken) -> ValidationResult
}Implementing this protocol on any class or struct allows it to be combined with other validator using the | or & operator.
The validation method returns a ValidationResult :
public enum ValidationResult {
    case Success
    case Failure(ErrorType)
    
    public var isValid : Bool
}You can implement a claim validator with the ClaimValidator struct :
public struct ClaimValidator<T> : JSONWebTokenValidatorType {
}let validator : ClaimValidator<Int> = ClaimValidator(key: "customClaim", transform: { (jsonValue : AnyObject) throws -> Int in
	guard let numberValue = jsonValue as? NSNumber else {
		throw ClaimValidatorError(message: "customClaim value \(jsonValue) is not the expected Number type")
	}
	return numberValue.integerValue
}).withValidator { 1..<4 ~= $0 }All registered claims validators are implemented :
- RegisteredClaimValidator.issuer:- issclaim is defined and is a- String
- RegisteredClaimValidator.subject:- subclaim is defined and is a- String
- RegisteredClaimValidator.audience:- audclaim is defined and is a- Stringor- [String]
- RegisteredClaimValidator.expiration:- expclaim is defined, is an- Integertransformable to- NSDate, and is after current date
- RegisteredClaimValidator.notBefore:- nbfclaim is defined, is an- Integertransformable to- NSDate, and is before current date
- RegisteredClaimValidator.issuedAt:- iatclaim is defined, is an- Integertransformable to- NSDate
- RegisteredClaimValidator.jwtIdentifier:- jticlaim is defined and is a- String
And it can be extended :
let myIssuerValidator = RegisteredClaimValidator.issuer.withValidator { $0 == "kreactive" }Implement the SignatureValidator protocol on any class or struct to add and unsupported signature algorithm validator.
public protocol SignatureValidator : JSONWebTokenValidatorType {
    func canVerifyWithSignatureAlgorithm(alg : SignatureAlgorithm) -> Bool
    func verify(input : NSData, signature : NSData) -> Bool
}Implement the TokenSigner protocol on any class or struct to sign token with unsupported signature algorithm.
public protocol TokenSigner {
    var signatureAlgorithm : SignatureAlgorithm {get}
    func sign(input : NSData) throws -> NSData
}