Skip to content

rogeriozambon/jwt.cr

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

jwt.cr

Build Status GitHub license

A simple JWT implementation in Crystal.

Installation

Add this to your application's shard.yml:

dependencies:
  jwt:
    github: rogeriozambon/jwt.cr

Usage

Encoding

adapter = JWT::Adapters::HS256.new("secret")
payload = {"foo" => "bar"}

JWT.encode(payload, adapter)
#=> eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIifQ.dtxWM6MIcgoeMgH87tGvsNDY6cHWL6MGW4LeYvnm1JA

Decoding

adapter = JWT::Adapters::HS256.new("secret")
token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIifQ.dtxWM6MIcgoeMgH87tGvsNDY6cHWL6MGW4LeYvnm1JA"

JWT.decode(token, adapter)
#=> {{"alg" => "HS256", "typ" => "JWT"}, {"foo" => "bar"}}

Middleware

require "jwt"
require "http/server"

adapter = JWT::Adapters::HS256.new("secret")

server = HTTP::Server.new("0.0.0.0", 8080, [
  JWT::Middleware.new(adapter)
])

puts "Listening on 8080 with JWT middleware.."
server.listen

Algorithms

  • None
  • HMAC (HS256, HS384, HS512)
  • RSA
  • ECDSA

Claims

Audience (aud)

require "jwt"

adapter = JWT::Adapters::HS256.new("secret")
payload = {"foo" => "bar", "aud" => ["guest", "visitor"]}

JWT.encode(payload, adapter)
#=> eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJhdWQiOlsiZ3Vlc3QiLCJ2aXNpdG9yIl19.S5BkkjkhjagYET12wz4W2cF8ATF1iVfpJ9OvbjMdCRU

JWT.decode(token, adapter)
#=> {{"alg" => "HS256", "typ" => "JWT"}, {"foo" => "bar", "aud" => ["guest", "visitor"]}}

When an audience doesn't match with that was passed to payload, an exception (JWT::Errors::Audience) will be thrown.

JWT.decode(token, adapter, {"aud" => "admin"})
#=> Invalid audience. (JWT::Errors::Audience)

Expiration (exp)

require "jwt"

adapter = JWT::Adapters::HS256.new("secret")
payload = {"foo" => "bar", "exp" => Time.now.epoch + 60}

JWT.encode(payload, adapter)
#=> eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJleHAiOjE0MDcxNTMyMzF9.ClzhXRBkpaJZw1QscBT_CD8yA1IQmWOTaokQn4fIGFc

JWT.decode(token, adapter)
#=> {{"alg" => "HS256", "typ" => "JWT"}, {"foo" => "bar", "exp" => 1407153257}}

After 60 seconds, the token expires and an exception (JWT::Errors::Expired) will be thrown:

JWT.decode(token, adapter)
#=> Token has expired. (JWT::Errors::Expired)

Issuer (iss)

require "jwt"

adapter = JWT::Adapters::HS256.new("secret")
payload = {"foo" => "bar", "iss" => "jwt.cr"}

JWT.encode(payload, adapter)
#=> eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJpc3MiOiJqd3QuY3IifQ.4lj020gUcpRg0r_4n8L7ZSn28BcSWGBeF3I7BaBSDDY

JWT.decode(token, adapter)
#=> {{"alg" => "HS256", "typ" => "JWT"}, {"foo" => "bar", "iss" => "jwt.cr"}}

When an issuer doesn't match with that was passed to payload, an exception (JWT::Errors::Issuer) will be thrown.

JWT.decode(token, adapter, {"iss" => "jwt"})
#=> Invalid issuer. (JWT::Errors::Issuer)

Not Before (nbf)

require "jwt"

adapter = JWT::Adapters::HS256.new("secret")
payload = {"foo" => "bar", "nbf" => Time.now.epoch + 60}

JWT.encode(payload, adapter)
#= > eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJuYmYiOjE0MDcxNTMyMDV9.s6PJj6dBxZPWpdzYjxw9h846x6IU05nRB41y43JNVMs

Before the 60 seconds ends, the token will not ready to use and an exception (JWT::Errors::NotReady) will be thrown:

JWT.decode(token, adapter)
#=> Token not ready. (JWT::Errors::NotReady)

Subject (sub)

require "jwt"

adapter = JWT::Adapters::HS256.new("secret")
payload = {"foo" => "bar", "sub" => "github"}

JWT.encode(payload, adapter)
#=> eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJzdWIiOiJnaXRodWIifQ.7r7_7tV4xzrQN1atQ7OP7O7eRVtb1l37dIYBjv5yJvg

JWT.decode(token, adapter)
#=> {{"alg" => "HS256", "typ" => "JWT"}, {"foo" => "bar", "sub" => "github"}}

When a subject doesn't match with that was passed to payload, an exception (JWT::Errors::Subject) will be thrown.

JWT.decode(token, adapter, {"sub" => "gitlab"})
#=> Invalid subject. (JWT::Errors::Subject)

Custom logger

It's possible to add a custom logger to replace the default behavior. You can add a logger that outputs to a file, for example. (Thanks @hugoabonizio)

log_file = File.open("./jwt.log", "w")

JWT::Logger.instance = Logger.new(log_file)

Specs

$ crystal spec

Contributors

About

A simple JWT implementation in Crystal

Topics

Resources

License

Code of conduct

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published