1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
|
# frozen-string-literal: true
require 'jwt'
require 'jwt/version'
module Rodauth
Feature.define(:jwt, :Jwt) do
depends :json
translatable_method :invalid_jwt_format_error_message, "invalid JWT format or claim in Authorization header"
auth_value_method :jwt_algorithm, "HS256"
auth_value_method :jwt_authorization_ignore, /\A(?:Basic|Digest) /
auth_value_method :jwt_authorization_remove, /\ABearer:?\s+/
auth_value_method :jwt_decode_opts, {}.freeze
auth_value_method :jwt_old_secret, nil
auth_value_method :jwt_session_key, nil
auth_value_method :jwt_symbolize_deeply?, false
auth_value_methods(
:jwt_secret,
:use_jwt?
)
auth_methods(
:jwt_session_hash,
:jwt_token,
:session_jwt,
:set_jwt_token
)
def_deprecated_alias :json_check_accept?, :jwt_check_accept?
def session
return @session if defined?(@session)
return super unless use_jwt?
s = {}
if jwt_token
unless session_data = jwt_payload
json_response[json_response_error_key] ||= invalid_jwt_format_error_message
_return_json_response
end
if jwt_session_key
session_data = session_data[jwt_session_key]
end
if session_data
if jwt_symbolize_deeply?
s = JSON.parse(JSON.generate(session_data), :symbolize_names=>true)
elsif scope.opts[:sessions_convert_symbols]
s = session_data
else
session_data.each{|k,v| s[k.to_sym] = v}
end
end
end
@session = s
end
def clear_session
super
set_jwt if use_jwt?
end
def jwt_secret
raise ConfigurationError, "jwt_secret not set"
end
def jwt_session_hash
jwt_session_key ? {jwt_session_key=>session} : session
end
def session_jwt
JWT.encode(jwt_session_hash, jwt_secret, jwt_algorithm)
end
def jwt_token
return @jwt_token if defined?(@jwt_token)
if (v = request.env['HTTP_AUTHORIZATION']) && v !~ jwt_authorization_ignore
@jwt_token = v.sub(jwt_authorization_remove, '')
end
end
def set_jwt_token(token)
set_response_header('authorization', token)
end
def use_jwt?
use_json?
end
def use_json?
jwt_token || super
end
def valid_jwt?
!!(jwt_token && jwt_payload)
end
private
def _jwt_decode_opts
jwt_decode_opts
end
if JWT.gem_version >= Gem::Version.new("2.4")
def _jwt_decode_secrets
secrets = [jwt_secret, jwt_old_secret]
secrets.compact!
secrets
end
# :nocov:
else
def _jwt_decode_secrets
jwt_secret
end
# :nocov:
end
def jwt_payload
return @jwt_payload if defined?(@jwt_payload)
@jwt_payload = JWT.decode(jwt_token, _jwt_decode_secrets, true, _jwt_decode_opts.merge(:algorithm=>jwt_algorithm))[0]
rescue JWT::DecodeError => e
rescue_jwt_payload(e)
end
def rescue_jwt_payload(_)
@jwt_payload = false
end
def set_session_value(key, value)
super
set_jwt if use_jwt?
value
end
def remove_session_value(key)
value = super
set_jwt if use_jwt?
value
end
def return_json_response
set_jwt
super
end
def set_jwt
set_jwt_token(session_jwt)
end
def use_scope_clear_session?
super && !use_jwt?
end
end
end
|