JWT::Authorizer
JWT::Authorizer makes authorization with JWT tokens simple. It allows creating and verifying JWT tokens according to claims set on specific JWT::Token class.
Installation
Add this line to your application's Gemfile:
gem 'jwt-authorizer'And then execute:
$ bundle
Or install it yourself as:
$ gem install jwt-authorizer
Usage
Configuration
You can configure your JWT::Token classes with .configuration and .configure options:
JWT::Token.configuration
JWT::Token.configure do |config|
config.expiry = 12 * 60 * 60
config.algorithm = "RS256"
config.rsa.authorized_keys = [OpenSSL::PKey::RSA.new(ENV["SECRET_KEY"])]
endJWT::Token have following options available:
-
algorithm- determines algorithm used on signing and verifying JWT tokens. Defaults to"HS256". -
hmac-HMACconfiguration:-
hmac.key- symmetric key used by HMAC algorithm
-
-
rsa|ecdsa-RSAandECDSAconfiguration:-
rsa.authorized_keys|ecdsa.authorized_keys-ArrayofOpenSSL::PKey::PKeyobjects with allowed public keys -
rsa.authorized_keys_file|ecdsa.authorized_keys_file- path to file containing authorized public keys in PEM format
-
-
expiry- sets default expiry for generated tokens. Defaults to 1 hour. It can be set tonilin order to not includeexpclaim in the token -
issuer- setsissclaim in the token. Defaults tonil. -
allowed_issuers- array of issuers that will be allowed on token verification. Defaults to empty array, tokens with any value inissclaim (and without this claim) will be valid. If array contains any elements, only listed issuers will be valid.
Default claims can be overriden during instantiation of JWT::Token classes:
JWT::Token.configuration.expiry #=> 3600 (offset)
JWT::Token.new(expiry: Time.utc(2018, 3, 1)).expiry #=> 1519862400 (timestamp)Generating tokens
To generate JWT token, create instance of JWT::Token. It accepts hash of additional claims you want in your token.
class MyToken < JWT::Token
claim :level, required: true
end
token = MyToken.new(level: :admin)
token.to_s # or token.to_jwt
#=> "eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1MjA0MTI2MTcsImxldmVsIjoiYWRtaW4ifQ.Ak8qDlxSG9IcPVHYnelQHPK5U6Rj5hBYQ5mmoznuYso"Verifying tokens
To verify token, use JWT::Token.verify method.
token = "eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1MjA0MTI2Nzd9.EgiqWfDjXzlJHTwaFn26X3iOl2gBkQv3fADtMsFIQDY"
JWT::Token.verify(token)
#=> #<JWT::Token @claims={"exp"=>1520412677, "iss"=>nil}>
JWT::Token.verify(nil)
# JWT::DecodeError: Nil JSON web token
JWT::Token.verify("eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjB9.nooope")
# JWT::VerificationError: Signature verification raisedClaims
You can use claims to define and verify non-standard claims.
class AdminToken < JWT::Token
claim :level, key: "lvl", required: true do |value|
raise JWT::DecodeError, "Level must be admin" unless value == "admin"
end
end
valid_token = "eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1MjA0MTI3ODksImxldmVsIjoiYWRtaW4ifQ.GGD0dXWg7v8BiEg8fsjmdCXQBryAHRpx_8AihyNVmgs"
AdminToken.verify(valid_token)
#=> #<AdminToken @claims={"exp"=>1520412789, "iss"=>nil, "lvl"=>"admin"}>
missing_claim = "eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1MjA0MTI3ODl9.efq_LuSpfp5VRwFl3rIf0FC_b2CCrpEC_oeDssvLDy4"
AdminToken.verify(missing_claim)
# JWT::Token::MissingClaim: Token is missing required claim: lvl
invalid_value = "eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1MjA0NTI3ODksImx2bCI6InJlZ3VsYXIifQ.EjXX9zhE4SpzFSlGIPD5l0xKtMKgWSbWa5smw3OvBEo"
AdminToken.verify(invalid_value)
# JWT::DecodeError: Level must be adminrequired option is by default set to false. If set to true, given claim must be present in verified token.
key options is by default the same as claim name. It corresponds to JSON inside JWT.
You can pass additional context to claims:
class AdminToken < JWT::Token
claim :path do |value, rack_request|
raise JWT::DecodeError, "invalid path" unless value == rack_request.path
end
end
AdminToken.verify(token, rack_request)See JWT::EndpointToken and it's spec for examples.
Default claims
Gem currently supports two of the standard claims: exp and iss.
Expiry
You can set expiry option on configuration to a preferred offset for generated tokens:
class LongLivedToken < JWT::Token
configuration.expiry = 2 * 365 * 24 * 60 * 60
end
token = LongLivedToken.new
Time.at token.expiry
#=> 2020-03-06 08:59:52 +0100Note that expiry option in configuration is an offset, while on token instance it's a timestamp.
On instance you can either assign timestamp, or a Time instance.
token = JWT::Token.new
token.expiry = Time.utc(2021, 1, 1)
token.expiry
#=> 1609459200
JWT::Token.new(expiry: Time.utc(2021, 1, 1)).expiry
#=> 1609459200exp claim will be validated if present.
Issuer
In order to validate issuer claim, set allowed_issuers on token class:
class MicroserviceToken < JWT::Token
configuration.allowed_issuers = ["apiservice", "cronservice"]
end
MicroserviceToken.verify(MicroserviceToken.new(issuer: "apiservice").to_jwt)
#=> #<MicroserviceToken @claims={"exp"=>1520413510, "iss"=>"apiservice"}>
MicroserviceToken.verify(MicroserviceToken.new(issuer: "otherservice").to_jwt)
# JWT::InvalidIssuerError: Invalid issuer. Expected ["apiservice", "cronservice"], received otherservice
MicroserviceToken.verify(MicroserviceToken.new(issuer: nil).to_jwt)
# JWT::InvalidIssuerError: Invalid issuer. Expected ["apiservice", "cronservice"], received <none>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 tags, and push the .gem file to rubygems.org.
Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/codesthq/jwt-authorizer. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant 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 JWT::Token project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.