Sandal Build Status Coverage Status Code Climate Dependency Status

A Ruby library for creating and reading JSON Web Tokens (JWT) draft-08, supporting JSON Web Signatures (JWS) draft-11 and JSON Web Encryption (JWE) draft-11. See the CHANGELOG for version history.

Installation

Add this line to your application's Gemfile:

gem 'sandal'

And then execute:

$ bundle

Or install it yourself as:

$ gem install sandal

Signed Tokens

All the JWA signature methods are supported:

  • ES256, ES384, ES512 (note: not supported on jruby)
  • HS256, HS384, HS512
  • RS256, RS384, RS512
  • none

Signing example:

claims = { 
  'iss' => 'example.org',
  'sub' => 'user@example.org',
  'exp' => (Time.now + 3600).to_i
}
signer = Sandal::Sig::ES256.new(File.read('/path/to/ec_private_key.pem'))
jws_token = Sandal.encode_token(claims, signer, { 
  'kid' => 'my ec key'
})

Decoding and validating example:

claims = Sandal.decode_token(jws_token) do |header|
  if header['kid'] == 'my ec key'
    Sandal::Sig::ES256.new(File.read('/path/to/ec_public_key.pem'))
  end
end

Keys for these examples can be generated by executing:

$ openssl ecparam -out ec_private_key.pem -name prime256v1 -genkey
$ openssl ec -out ec_public_key.pem -in ec_private_key.pem -pubout

Encrypted Tokens

All the JWA encryption methods are supported:

  • A128CBC+HS256, A256CBC+HS512
  • A128GCM, A256GCM (note: requires ruby 2.0.0 or later)

Some of the JWA key encryption algorithms are supported at the moment. The key wrap algorithms don't appear to exist in Ruby so they're not likely to be supported in the near future, but ECDH-ES should be soon:

  • RSA1_5
  • RSA-OAEP
  • direct

Encrypting example (assumes use of the jws_token from the signing examples, as typically JWE tokens will be used to wrap JWS tokens):

alg = Sandal::Enc::Alg::RSA_OAEP.new(File.Read('/path/to/rsa_public_key.pem'))
encrypter = Sandal::Enc::A128GCM.new(alg)
jwe_token = Sandal.encrypt_token(jws_token, encrypter, {
  'kid': 'your rsa key',
  'cty': 'JWT'
})

Decrypting example:

jws_token = Sandal.decode_token(jwe_token) do |header|
  if header['kid'] == 'your rsa key'
    alg = Sandal::Enc::Alg::RSA_OAEP.new(File.Read('/path/to/rsa_private_key.pem'))
    Sandal::Enc::A128GCM.new(alg)
  end
end

Keys for these examples can be generated by executing:

$ openssl genrsa -out rsa_private_key.pem 2048
$ openssl rsa -out rsa_public_key.pem -in rsa_private_key.pem -pubout

Validation Options

You can change the default validation options, for example if you only want to accept tokens from 'example.org' with a maximum clock skew of one minute:

Sandal.default! valid_iss: ['example.org'], max_clock_skew: 60

Sometimes while developing it can be useful to turn off some validation options just to get things working (don't do this in production!):

Sandal.default! ignore_signature: true, ignore_exp: true

These options can also be configured on a per-token basis by using a second options parameter in the block passed to the decode method.

Contributing

  1. Fork it
  2. Create your feature branch: git checkout -b my-new-feature
  3. Commit your changes: git commit -am 'Add some feature'
  4. Push to the branch: git push origin my-new-feature
  5. Create a new Pull Request