Class: RackJwtAegis::JwtValidator
- Inherits:
-
Object
- Object
- RackJwtAegis::JwtValidator
- Defined in:
- lib/rack_jwt_aegis/jwt_validator.rb
Overview
JWT token validation and payload verification
Handles JWT token decoding, signature verification, and payload validation including claims verification and type checking based on configuration.
Instance Method Summary collapse
-
#initialize(config) ⇒ JwtValidator
constructor
Initialize the JWT validator.
-
#validate(token) ⇒ Hash
Validate and decode a JWT token.
-
#validate_claim_types(payload) ⇒ Object
private
Validate the data types of specific claims in the payload.
-
#validate_payload_structure(payload) ⇒ Object
private
Validate the structure and content of the JWT payload.
-
#validate_required_claims(payload) ⇒ Object
private
Validate that all required claims are present in the payload.
Constructor Details
#initialize(config) ⇒ JwtValidator
Initialize the JWT validator
32 33 34 |
# File 'lib/rack_jwt_aegis/jwt_validator.rb', line 32 def initialize(config) @config = config end |
Instance Method Details
#validate(token) ⇒ Hash
Validate and decode a JWT token
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 |
# File 'lib/rack_jwt_aegis/jwt_validator.rb', line 42 def validate(token) # Decode JWT with verification payload, _header = JWT.decode( token, @config.jwt_secret, true, # verify signature { algorithm: @config.jwt_algorithm, verify_expiration: true, verify_not_before: true, verify_iat: true, verify_aud: false, # Not validating audience by default verify_iss: false, # Not validating issuer by default verify_sub: false, # Not validating subject by default }, ) # Validate payload structure validate_payload_structure(payload) payload rescue JWT::ExpiredSignature raise AuthenticationError, 'JWT token has expired' rescue JWT::ImmatureSignature raise AuthenticationError, 'JWT token not yet valid' rescue JWT::InvalidIatError raise AuthenticationError, 'JWT token issued in the future' rescue JWT::VerificationError raise AuthenticationError, 'JWT signature verification failed' rescue JWT::DecodeError => e raise AuthenticationError, "Invalid JWT token: #{e.}" rescue StandardError => e raise AuthenticationError, "JWT validation error: #{e.}" end |
#validate_claim_types(payload) ⇒ Object (private)
Validate the data types of specific claims in the payload
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 |
# File 'lib/rack_jwt_aegis/jwt_validator.rb', line 116 def validate_claim_types(payload) user_id = payload[@config.payload_key(:user_id).to_s] # User ID should be numeric or string if user_id.to_s.empty? || (!user_id.is_a?(Numeric) && !user_id.is_a?(String)) raise AuthenticationError, 'Invalid user_id format in JWT payload' end # Tenant ID should be numeric or string (if present) if @config.validate_tenant_id? tenant_id = payload[@config.payload_key(:tenant_id).to_s] if tenant_id.to_s.empty? || (!tenant_id.is_a?(Numeric) && !tenant_id.is_a?(String)) raise AuthenticationError, 'Invalid tenant_id format in JWT payload' end end # Company group domain should be string (if present) if @config.validate_subdomain? subdomain = payload[@config.payload_key(:subdomain).to_s] if subdomain.to_s.empty? || !subdomain.is_a?(String) raise AuthenticationError, 'Invalid subdomain format in JWT payload' end end # Company slugs should be array (if present) return unless @config.validate_pathname_slug? pathname_slugs = payload[@config.payload_key(:pathname_slugs).to_s] return unless pathname_slugs && !pathname_slugs.is_a?(Array) raise AuthenticationError, 'Invalid pathname_slugs format in JWT payload - must be array' end |
#validate_payload_structure(payload) ⇒ Object (private)
Validate the structure and content of the JWT payload
83 84 85 86 87 88 89 90 91 92 |
# File 'lib/rack_jwt_aegis/jwt_validator.rb', line 83 def validate_payload_structure(payload) # Ensure payload is a hash raise AuthenticationError, 'Invalid JWT payload structure' unless payload.is_a?(Hash) # Validate required claims based on enabled features validate_required_claims(payload) # Validate claim types validate_claim_types(payload) end |
#validate_required_claims(payload) ⇒ Object (private)
Validate that all required claims are present in the payload
98 99 100 101 102 103 104 105 106 107 108 109 110 |
# File 'lib/rack_jwt_aegis/jwt_validator.rb', line 98 def validate_required_claims(payload) # Always require user identification required_claims = [@config.payload_key(:user_id)] required_claims << @config.payload_key(:subdomain) if @config.validate_subdomain? required_claims << @config.payload_key(:tenant_id) if @config.validate_tenant_id? required_claims << @config.payload_key(:pathname_slugs) if @config.validate_pathname_slug? required_claims << @config.payload_key(:role_ids) if @config.rbac_enabled? missing_claims = required_claims.select { |claim| payload[claim.to_s].to_s.empty? } return if missing_claims.empty? raise AuthenticationError, "JWT payload missing required claims: #{missing_claims.join(', ')}" end |