Module: Sandal
- Defined in:
- lib/sandal.rb,
lib/sandal/enc.rb,
lib/sandal/sig.rb,
lib/sandal/json.rb,
lib/sandal/util.rb,
lib/sandal/claims.rb,
lib/sandal/sig/es.rb,
lib/sandal/sig/hs.rb,
lib/sandal/sig/rs.rb,
lib/sandal/enc/alg.rb,
lib/sandal/version.rb,
lib/sandal/enc/agcm.rb,
lib/sandal/enc/acbc_hs.rb,
lib/sandal/enc/alg/rsa.rb,
lib/sandal/enc/alg/direct.rb
Overview
A library for creating and reading JSON Web Tokens (JWT), supporting JSON Web Signatures (JWS) and JSON Web Encryption (JWE).
Currently supports draft-07 of the JWT spec, and draft-10 of the JWS and JWE specs.
Defined Under Namespace
Modules: Claims, Enc, Json, Sig Classes: ClaimError, Error, ExpiredTokenError, InvalidTokenError, KeyError, TokenError, UnsupportedTokenError
Constant Summary collapse
- DEFAULT_OPTIONS =
The default options for token handling.
- ignore_exp
-
Whether to ignore the expiry date of the token. This setting is just to help get things working and should always be false in real apps!
- ignore_nbf
-
Whether to ignore the not-before date of the token. This setting is just to help get things working and should always be false in real apps!
- ignore_signature
-
Whether to ignore the signature of signed (JWS) tokens. This setting is just tohelp get things working and should always be false in real apps!
- max_clock_skew
-
The maximum clock skew, in seconds, when validating times. If your server time is out of sync with the token server then this can be increased to take that into account. It probably shouldn’t be more than about 300.
- signature_policy
-
The policy for requiring signatures in tokens. The possible values are:
-
:strict (default) - The innermost token must be signed. This is the recommended policy.
-
:none - No signature is required. This really isn’t recommended.
-
- valid_iss
-
A list of valid token issuers, if validation of the issuer claim is required.
- valid_aud
-
A list of valid audiences, if validation of the audience claim is required.
{ ignore_exp: false, ignore_nbf: false, ignore_signature: false, max_clock_skew: 0, signature_policy: :strict, valid_iss: [], valid_aud: [] }
- VERSION =
The semantic version of the library.
"0.6.0"
Class Method Summary collapse
-
.decode_token(token, depth = 16) {|header, options| ... } ⇒ Hash or String
Decodes and validates a signed and/or encrypted JSON Web Token, recursing into any nested tokens, and returns the payload.
-
.default!(defaults) ⇒ Hash
Overrides the default options.
-
.encode_token(payload, signer, header_fields = nil) ⇒ String
Creates a signed JSON Web Token.
-
.encrypt_token(payload, encrypter, header_fields = nil) ⇒ String
Creates an encrypted JSON Web Token.
-
.is_encrypted?(token) ⇒ Boolean
Checks whether a token is encrypted.
-
.is_signed?(token) ⇒ Boolean
Checks whether a token is signed.
Class Method Details
.decode_token(token, depth = 16) {|header, options| ... } ⇒ Hash or String
Decodes and validates a signed and/or encrypted JSON Web Token, recursing into any nested tokens, and returns the payload.
The block is called with the token header as the first parameter, and should return the appropriate signature or decryption method to either validate the signature or decrypt the token as applicable. When the tokens are nested, this block will be called once per token. It can optionally have a second options parameter which can be used to override the DEFAULT_OPTIONS on a per-token basis; options are not persisted between yields.
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 |
# File 'lib/sandal.rb', line 162 def self.decode_token(token, depth = 16) parts = token.split(".") decoded_parts = decode_token_parts(parts) header = decoded_parts[0] = DEFAULT_OPTIONS.clone decoder = yield header, if block_given? if is_encrypted?(parts) payload = decoder.decrypt(parts) if header.has_key?("zip") unless header["zip"] == "DEF" raise Sandal::InvalidTokenError, "Invalid zip algorithm." end payload = Zlib::Inflate.inflate(payload) end else payload = decoded_parts[1] unless [:ignore_signature] validate_signature(parts, decoded_parts[2], decoder) end end if header.has_key?("cty") && header["cty"] =~ /\AJWT\Z/i if depth > 0 if block_given? decode_token(payload, depth - 1, &Proc.new) else decode_token(payload, depth - 1) end else payload end else if [:signature_policy] == :strict && !is_signed?(parts) raise Sandal::UnsupportedTokenError, "The innermost token is not signed." end parse_and_validate(payload, ) end end |
.default!(defaults) ⇒ Hash
Overrides the default options.
75 76 77 |
# File 'lib/sandal.rb', line 75 def self.default!(defaults) DEFAULT_OPTIONS.merge!(defaults) end |
.encode_token(payload, signer, header_fields = nil) ⇒ String
Creates a signed JSON Web Token.
109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
# File 'lib/sandal.rb', line 109 def self.encode_token(payload, signer, header_fields = nil) signer ||= Sandal::Sig::NONE header = {} header["alg"] = signer.name header = header_fields.merge(header) if header_fields header = Sandal::Json.dump(header) payload = Sandal::Json.dump(payload) unless payload.is_a?(String) sec_input = [header, payload].map { |p| Sandal::Util.jwt_base64_encode(p) }.join(".") signature = signer.sign(sec_input) [sec_input, Sandal::Util.jwt_base64_encode(signature)].join(".") end |
.encrypt_token(payload, encrypter, header_fields = nil) ⇒ String
Creates an encrypted JSON Web Token.
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 |
# File 'lib/sandal.rb', line 130 def self.encrypt_token(payload, encrypter, header_fields = nil) header = {} header["enc"] = encrypter.name header["alg"] = encrypter.alg.name header = header_fields.merge(header) if header_fields if header.has_key?("zip") unless header["zip"] == "DEF" raise ArgumentError, "Invalid zip algorithm." end payload = Zlib::Deflate.deflate(payload, Zlib::BEST_COMPRESSION) end encrypter.encrypt(Sandal::Json.dump(header), payload) end |
.is_encrypted?(token) ⇒ Boolean
Checks whether a token is encrypted.
83 84 85 86 87 88 89 |
# File 'lib/sandal.rb', line 83 def self.is_encrypted?(token) if token.is_a?(String) token.count(".") == 4 else token.count == 5 end end |
.is_signed?(token) ⇒ Boolean
Checks whether a token is signed.
95 96 97 98 99 100 101 |
# File 'lib/sandal.rb', line 95 def self.is_signed?(token) if token.is_a?(String) !token.end_with?(".") && token.count(".") == 2 else token.count == 3 && !token[2].nil? && !token[2].empty? end end |