Sinatra::Jwt
Installation
Install the gem and add to the application's Gemfile by executing:
$ bundle add sinatra-jwt
If bundler is not being used to manage dependencies, install the gem by executing:
$ gem install sinatra-jwt
Usage
require "sinatra/jwt"
class Application < Sinatra::Base
register Sinatra::Jwt
end
Use a single key
If you wish to use a single key you can provide it directly
require "sinatra/jwt"
class Application < Sinatra::Base
register Sinatra::Jwt
jwt_auth "superSecretKey", "HS512"
end
Use a JWK
By default the extension will try to load a file called jwk.json
from the current path containing the keys if jwt_auth
was not called with a key.
You should keep in mind that if you are using jwk the header portion of the jwt has to contain the key id:
{
...
"kid": "lol"
}
An example JWT:
eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCIsImtpZCI6ImxvbCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMiwicmlnaHRzIjpbInJlYWRfYXBpIl19.RxOADRpmII2n14Och-34c0w-3NgB74kRi_XgERkO4joiDKYesSZnopL_yMtzVqdkHtLGS_SlULQjudEeQ7q9eg
that contains the following data:
HEADER
{
"alg": "HS512",
"typ": "JWT",
"kid": "lol"
}
PAYLOAD
{
"sub": "1234567890",
"name": "John Doe",
"admin": true,
"iat": 1516239022,
"rights": ["read_api"]
}
An example jwk file containing the key could look like this:
{
"keys": [
{
"kid": "lol",
"k": "superSecretKey",
"kty": "oct"
}
]
}
The file can contain as many keys as you want all with different algorithms.
Configure JWK loading
Files
You can change the file that is loaded by either hardcoding the path
require "sinatra/jwt"
class Application < Sinatra::Base
register Sinatra::Jwt
jwk_file "/path/to/jwk/file.json"
end
or using the env helper method that takes the path from the environment variables
require "sinatra/jwt"
class Application < Sinatra::Base
register Sinatra::Jwt
jwk_file_env "JWK"
# is equivalent to:
# jwk_file ENV["JWK"]
end
Strings
You can change the file that is loaded by either hardcoding the path
require "sinatra/jwt"
class Application < Sinatra::Base
register Sinatra::Jwt
jwk_string '{"keys":[{"kid":"lol","k":"superSecretKey","kty":"oct"}]}'
end
or using the env helper method that takes the path from the environment variables
require "sinatra/jwt"
class Application < Sinatra::Base
register Sinatra::Jwt
jwk_string_env "JWK"
# is equivalent to:
# jwk_string ENV["JWK"]
end
Protect a route
Require a valid jwt
get "/protected", :auth => true do
"Hello world login"
end
Allow hitting the next matching url
get "/protected", :auth => [{next: true}] do
"Hello world login"
end
get "/protected" do
"Hello world login"
end
Require a valid jwt as well as specific payload
jwt_data_contains_diff Sinatra::Jwt::TopLevelKeyArrayDiff
get "/protected", :auth => [{contains: {rights: ["read_api"]}}] do
"Hello world login"
end
TopLevelKeyArrayDiff
The TopLevelKeyArrayDiff only works on a simple top level and array diff level.
So only:
{
"SOMEKEY": "SOMEVALUE can be array, object, string, number etc"
}
If the value is an array it can also detect if required attributes are in the array. For any other value type it will cause a missing rights error if the objects are not identical.
Custom Decoder
You can use a custom decoder by implementing an object that has a decode
method following the signature of the jwt gem https://github.com/jwt/ruby-jwt
require "base64"
require "json"
require "sinatra/jwt"
class DummyDecoder
def self.decode(token, key = nil, verify = false, options = {})
raise Sinatra::Jwt::JwtDummyDecoderError, "DummyDecoder should not be used in production" if ENV["RACK_ENV"] != "development"
encoded_header, encoded_payload, signature = token.split(".")
[JSON.parse(Base64.decode64(encoded_payload)), JSON.parse(Base64.decode64(encoded_header))]
end
end
class Application < Sinatra::Base
register Sinatra::Jwt
jwt_decoder DummyDecoder
get "/protected", :auth => true do
puts jwt_payload
"Hello world login"
end
end
This decoder is bundled with the extension but will cause unauthorized calls in any other environment than development
require "sinatra/jwt"
class Application < Sinatra::Base
register Sinatra::Jwt
jwt_decoder Sinatra::Jwt::DummyDecoder
get "/protected", :auth => true do
puts jwt_payload
"Hello world login"
end
end
Development
After checking out the repo, run bin/setup
to install dependencies. Then, run rake spec
to run the tests. You can also run bin/console
for an interactive prompt that will allow you to experiment.
To install this gem onto your local machine, run bundle exec rake install
. To release a new version, update the version number in version.rb
, and then run bundle exec rake release
, which will create a git tag for the version, push git commits and the created tag, and push the .gem
file to rubygems.org.
Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/suddani/sinatra-jwt. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the code of conduct.
License
The gem is available as open source under the terms of the MIT License.
Code of Conduct
Everyone interacting in the Sinatra::Jwt project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.