Applications often need to have a public/private keypair so sign messages. This gem manages your application level key pairs with automatic rotation and support for encoding and decoding JWTs.
Note: This gem is intended to work within Rails applications. It can probably be adjusted easily to also work for non-rails / sinatra project but that’s out of scope for now.
Add gem
Add this line to your application’s Gemfile:
gem 'keypairs'
The of course run bundle install
.
Copy migration
The default migration file can be copied to your app with:
bundle exec rails keypairs:install:migrations
Then of course run bundle exec rails db:migrate
Setup encryption key
The private keys are encrypted with the lockbox gem. In order for this to work, you need to set the master key as described in the readme, but the easiest thing is to set the environment variable LOCKBOX_MASTER_KEY
to a sufficient long string (you can generate one with Lockbox.generate_key
).
The central point of this gem is the Keypair
model which is backed by the keypairs
table. If you need to sign messages, you can get the current keypair with the Keypair.current
method. This method performs the rotation of the keypairs if required.
You can access the private an public key of the keypair (OpenSSL::PKey::RSA
) and encrypt and decrypt messages with them:
encoded_message = Keypair.current.private_key.private_decrypt('foobar')
Keypair.current.public_key.public_decrypt(encoded_message)
# => 'foobar'
You can encode and decode JWTs directly on the class:
payload = { foo: 'bar' }
id_token = Keypair.jwt_encode(payload)
decoded = Keypair.jwt_decode(id_token)
It’s almost always a good idea to add a subject to your payload and pass the same subject during decoding. That way you know that users don’t use a key for other purposes (for example a key intended for an OAuth2 flow used as a session key). So for example:
subject = 'MyAppSession'
payload = { foo: 'bar', subject: subject }
id_token = Keypair.jwt_encode(payload)
decoded = Keypair.jwt_decode(id_token, subject: subject)
If you want others to validate your messages based on the public keys, you can share the JWK version of you current keys by adding them to your config/routes.rb
:
get :jwks, to: Keypairs::PublicKeysController.action(:index)
Publishing a new version is handled by the publish workflow. This workflow publishes a GitHub release to rubygems and GitHub package registry with the version defined in the release.
Bug reports and pull requests are welcome on GitHub at https://github.com/Drieam/keypairs.
The gem is available as open source under the terms of the MIT License.