Class: JwtAuthCognito::JwtValidator
- Inherits:
-
Object
- Object
- JwtAuthCognito::JwtValidator
- Defined in:
- lib/jwt_auth_cognito/jwt_validator.rb
Class Method Summary collapse
-
.create_cognito_validator(config = nil) ⇒ Object
Create a convenience factory method.
Instance Method Summary collapse
-
#calculate_secret_hash(identifier) ⇒ Object
Calculate secret hash for Cognito operations (when client secret is configured).
- #decode_token(token) ⇒ Object
- #extract_api_key_from_header(api_key_header) ⇒ Object
- #extract_api_key_from_headers(headers) ⇒ Object
-
#extract_token_from_header(authorization_header) ⇒ Object
Utility methods inspired by Node.js package.
- #get_time_to_expiry(token) ⇒ Object
- #get_token_info(token) ⇒ Object
-
#has_client_secret? ⇒ Boolean
Check if client secret is configured.
-
#initialize(config = JwtAuthCognito.configuration) ⇒ JwtValidator
constructor
A new instance of JwtValidator.
- #initialize! ⇒ Object
- #is_token_expired?(token) ⇒ Boolean
- #revoke_token(token, user_id: nil) ⇒ Object
- #revoke_user_tokens(user_id) ⇒ Object
- #validate_access_token(token) ⇒ Object
- #validate_id_token(token) ⇒ Object
- #validate_multiple_tokens(tokens) ⇒ Object
- #validate_token(token, options = {}) ⇒ Object
- #validate_token_enriched(token, api_key = nil, options = {}) ⇒ Object
- #validate_token_with_api_key(token, api_key = nil, options = {}) ⇒ Object
Constructor Details
#initialize(config = JwtAuthCognito.configuration) ⇒ JwtValidator
Returns a new instance of JwtValidator.
7 8 9 10 11 12 13 14 |
# File 'lib/jwt_auth_cognito/jwt_validator.rb', line 7 def initialize(config = JwtAuthCognito.configuration) @config = config @jwks_service = JwksService.new(config) @blacklist_service = TokenBlacklistService.new(config) @api_key_validator = config.enable_api_key_validation ? ApiKeyValidator.new(config) : nil @user_data_service = config.enable_user_data_retrieval ? UserDataService.new(nil, config.user_data_config) : nil @initialized = false end |
Class Method Details
.create_cognito_validator(config = nil) ⇒ Object
Create a convenience factory method
215 216 217 218 219 220 221 222 223 224 225 |
# File 'lib/jwt_auth_cognito/jwt_validator.rb', line 215 def self.create_cognito_validator(config = nil) if config old_config = JwtAuthCognito.configuration JwtAuthCognito.configure { |_c| config } validator = new JwtAuthCognito.instance_variable_set(:@configuration, old_config) validator else new end end |
Instance Method Details
#calculate_secret_hash(identifier) ⇒ Object
Calculate secret hash for Cognito operations (when client secret is configured)
184 185 186 |
# File 'lib/jwt_auth_cognito/jwt_validator.rb', line 184 def calculate_secret_hash(identifier) @config.calculate_secret_hash(identifier) end |
#decode_token(token) ⇒ Object
159 160 161 162 163 |
# File 'lib/jwt_auth_cognito/jwt_validator.rb', line 159 def decode_token(token) JWT.decode(token, nil, false).first rescue JWT::DecodeError => e { error: "Failed to decode token: #{e.}" } end |
#extract_api_key_from_header(api_key_header) ⇒ Object
136 137 138 139 140 141 |
# File 'lib/jwt_auth_cognito/jwt_validator.rb', line 136 def extract_api_key_from_header(api_key_header) # Support common API key header formats return nil unless api_key_header api_key_header.strip end |
#extract_api_key_from_headers(headers) ⇒ Object
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 |
# File 'lib/jwt_auth_cognito/jwt_validator.rb', line 143 def extract_api_key_from_headers(headers) # Check various common API key header names (case insensitive) api_key_headers = %w[x-api-key X-API-Key X-API-KEY X-Api-Key] api_key_headers.each do |header_name| # Convert headers to a case-insensitive hash for lookup header_key = headers.keys.find { |key| key.downcase == header_name.downcase } next unless header_key value = headers[header_key] return extract_api_key_from_header(value) if value end nil end |
#extract_token_from_header(authorization_header) ⇒ Object
Utility methods inspired by Node.js package
129 130 131 132 133 134 |
# File 'lib/jwt_auth_cognito/jwt_validator.rb', line 129 def extract_token_from_header() return nil unless match = .match(/\ABearer (.+)\z/) match ? match[1] : nil end |
#get_time_to_expiry(token) ⇒ Object
203 204 205 206 207 208 209 210 211 212 |
# File 'lib/jwt_auth_cognito/jwt_validator.rb', line 203 def get_time_to_expiry(token) payload = decode_token(token) return nil if payload.is_a?(Hash) && payload[:error] exp = payload['exp'] return nil unless exp seconds = exp - Time.now.to_i seconds.positive? ? seconds : 0 end |
#get_token_info(token) ⇒ Object
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 |
# File 'lib/jwt_auth_cognito/jwt_validator.rb', line 165 def get_token_info(token) payload = decode_token(token) return payload if payload.is_a?(Hash) && payload[:error] { sub: payload['sub'], username: payload['cognito:username'] || payload['username'], email: payload['email'], token_use: payload['token_use'], client_id: payload['aud'], issued_at: payload['iat'] ? Time.at(payload['iat']) : nil, expires_at: payload['exp'] ? Time.at(payload['exp']) : nil, not_before: payload['nbf'] ? Time.at(payload['nbf']) : nil, jti: payload['jti'], has_client_secret: @config.has_client_secret? } end |
#has_client_secret? ⇒ Boolean
Check if client secret is configured
189 190 191 |
# File 'lib/jwt_auth_cognito/jwt_validator.rb', line 189 def has_client_secret? @config.has_client_secret? end |
#initialize! ⇒ Object
16 17 18 19 20 21 22 23 24 25 26 27 28 |
# File 'lib/jwt_auth_cognito/jwt_validator.rb', line 16 def initialize! return if @initialized begin @jwks_service.initialize! @blacklist_service.initialize! if @blacklist_service.respond_to?(:initialize!) @user_data_service&.initialize! @initialized = true rescue StandardError => e ErrorUtils.log_error(e, 'JWT Validator initialization failed') raise JwtAuthCognito::ConfigurationError, ErrorUtils::JWT_ERROR_MESSAGES['INITIALIZATION_FAILED'] end end |
#is_token_expired?(token) ⇒ Boolean
193 194 195 196 197 198 199 200 201 |
# File 'lib/jwt_auth_cognito/jwt_validator.rb', line 193 def is_token_expired?(token) payload = decode_token(token) return true if payload.is_a?(Hash) && payload[:error] exp = payload['exp'] return false unless exp Time.now.to_i >= exp end |
#revoke_token(token, user_id: nil) ⇒ Object
120 121 122 |
# File 'lib/jwt_auth_cognito/jwt_validator.rb', line 120 def revoke_token(token, user_id: nil) @blacklist_service.add_to_blacklist(token, user_id: user_id) end |
#revoke_user_tokens(user_id) ⇒ Object
124 125 126 |
# File 'lib/jwt_auth_cognito/jwt_validator.rb', line 124 def revoke_user_tokens(user_id) @blacklist_service.invalidate_user_tokens(user_id) end |
#validate_access_token(token) ⇒ Object
100 101 102 103 104 105 106 |
# File 'lib/jwt_auth_cognito/jwt_validator.rb', line 100 def validate_access_token(token) result = validate_token(token) return { valid: false, error: 'Token is not an access token' } if result[:valid] && result[:payload]['token_use'] != 'access' result end |
#validate_id_token(token) ⇒ Object
108 109 110 111 112 113 114 |
# File 'lib/jwt_auth_cognito/jwt_validator.rb', line 108 def validate_id_token(token) result = validate_token(token) return { valid: false, error: 'Token is not an ID token' } if result[:valid] && result[:payload]['token_use'] != 'id' result end |
#validate_multiple_tokens(tokens) ⇒ Object
116 117 118 |
# File 'lib/jwt_auth_cognito/jwt_validator.rb', line 116 def validate_multiple_tokens(tokens) tokens.map { |token| validate_token(token) } end |
#validate_token(token, options = {}) ⇒ Object
30 31 32 |
# File 'lib/jwt_auth_cognito/jwt_validator.rb', line 30 def validate_token(token, = {}) validate_token_with_api_key(token, nil, ) end |
#validate_token_enriched(token, api_key = nil, options = {}) ⇒ Object
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 |
# File 'lib/jwt_auth_cognito/jwt_validator.rb', line 65 def validate_token_enriched(token, api_key = nil, = {}) # First, perform standard token validation basic_result = validate_token_with_api_key(token, api_key, ) # If basic validation fails, return early return basic_result unless basic_result[:valid] && basic_result[:payload] # If user data retrieval is not enabled, return basic result return basic_result unless @config.enable_user_data_retrieval && @user_data_service # Extract user ID from the token user_id = basic_result[:payload]['sub'] unless user_id puts 'Token does not contain sub claim, cannot retrieve user data' return basic_result end begin # Get comprehensive user data from Redis user_data = @user_data_service.get_comprehensive_user_data(user_id) # Add user data to the result enriched_result = basic_result.dup enriched_result[:user_permissions] = user_data['permissions'] enriched_result[:user_organizations] = user_data['organizations'] enriched_result[:applications] = user_data['applications'] enriched_result rescue StandardError => e ErrorUtils.log_error(e, 'User data retrieval failed') # Return basic result even if user data retrieval fails basic_result end end |
#validate_token_with_api_key(token, api_key = nil, options = {}) ⇒ Object
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 |
# File 'lib/jwt_auth_cognito/jwt_validator.rb', line 34 def validate_token_with_api_key(token, api_key = nil, = {}) @config.validate! # Validate API key if provided and enabled api_key_data = nil if api_key && @config.enable_api_key_validation && @api_key_validator api_key_result = @api_key_validator.validate_api_key(api_key) return { valid: false, error: api_key_result[:error] || 'API key validation failed' } unless api_key_result[:valid] api_key_data = api_key_result[:key_data] end # Check blacklist first return { valid: false, error: 'Token has been revoked' } if @blacklist_service.is_blacklisted?(token) # Choose validation method based on configuration result = case @config.validation_mode when :secure validate_token_secure(token, ) when :basic validate_token_basic(token, ) else raise ConfigurationError, "Invalid validation_mode: #{@config.validation_mode}" end # Add API key data to result if validation succeeded result[:api_key] = api_key_data if result[:valid] && api_key_data result end |