diff --git a/lib/intercom-rails/config.rb b/lib/intercom-rails/config.rb index 925e778..c6dfe2f 100644 --- a/lib/intercom-rails/config.rb +++ b/lib/intercom-rails/config.rb @@ -145,6 +145,7 @@ def self.company_association=(*) config_group :jwt do config_accessor :enabled + config_accessor :expiry config_accessor :signed_user_fields do |value| unless value.nil? || (value.kind_of?(Array) && value.all? { |v| v.kind_of?(Symbol) || v.kind_of?(String) }) raise ArgumentError, "jwt.signed_user_fields must be an array of symbols or strings" diff --git a/lib/intercom-rails/script_tag.rb b/lib/intercom-rails/script_tag.rb index c482b29..3f368af 100644 --- a/lib/intercom-rails/script_tag.rb +++ b/lib/intercom-rails/script_tag.rb @@ -18,7 +18,7 @@ class ScriptTag include ::ActionView::Helpers::TagHelper attr_reader :user_details, :company_details, :show_everywhere, :session_duration - attr_accessor :secret, :widget_options, :controller, :nonce, :encrypted_mode_enabled, :encrypted_mode, :jwt_enabled + attr_accessor :secret, :widget_options, :controller, :nonce, :encrypted_mode_enabled, :encrypted_mode, :jwt_enabled, :jwt_expiry def initialize(options = {}) self.secret = options[:secret] || Config.api_secret @@ -27,6 +27,7 @@ def initialize(options = {}) @show_everywhere = options[:show_everywhere] @session_duration = session_duration_from_config self.jwt_enabled = options[:jwt_enabled] || Config.jwt.enabled + self.jwt_expiry = options[:jwt_expiry] || Config.jwt.expiry initial_user_details = if options[:find_current_user_details] find_current_user_details @@ -124,10 +125,11 @@ def intercom_javascript def generate_jwt return nil unless user_details[:user_id].present? - payload = { - user_id: user_details[:user_id].to_s, - exp: 24.hours.from_now.to_i - } + payload = { user_id: user_details[:user_id].to_s } + + if jwt_expiry + payload[:exp] = jwt_expiry.from_now.to_i + end if Config.jwt.signed_user_fields.present? Config.jwt.signed_user_fields.each do |field| diff --git a/spec/script_tag_spec.rb b/spec/script_tag_spec.rb index a7273fd..2f385eb 100644 --- a/spec/script_tag_spec.rb +++ b/spec/script_tag_spec.rb @@ -332,7 +332,7 @@ def user expect(script_tag.intercom_settings[:user_hash]).to be_nil end - it 'generates a valid JWT with correct payload' do + it 'generates a valid JWT with the correct user_id' do user_id = '1234' script_tag = ScriptTag.new( user_details: { user_id: user_id }, @@ -343,7 +343,6 @@ def user decoded_payload = JWT.decode(jwt, 'super-secret', true, { algorithm: 'HS256' })[0] expect(decoded_payload['user_id']).to eq(user_id) - expect(decoded_payload['exp']).to be_within(5).of(24.hours.from_now.to_i) end it 'does not generate JWT when user_id is missing' do @@ -467,6 +466,48 @@ def user expect(script_tag.intercom_settings[:name]).to eq('Test User') end end + + context 'JWT expiry' do + it 'includes expiry when configured' do + IntercomRails.config.jwt.expiry = 12.hours + script_tag = ScriptTag.new( + user_details: { user_id: '1234' }, + jwt_enabled: true + ) + + jwt = script_tag.intercom_settings[:intercom_user_jwt] + decoded_payload = JWT.decode(jwt, 'super-secret', true, { algorithm: 'HS256' })[0] + + expect(decoded_payload['exp']).to be_within(5).of(12.hours.from_now.to_i) + end + + it 'omits expiry when not configured' do + IntercomRails.config.jwt.expiry = nil + script_tag = ScriptTag.new( + user_details: { user_id: '1234' }, + jwt_enabled: true + ) + + jwt = script_tag.intercom_settings[:intercom_user_jwt] + decoded_payload = JWT.decode(jwt, 'super-secret', true, { algorithm: 'HS256' })[0] + + expect(decoded_payload).not_to have_key('exp') + end + + it 'allows overriding expiry via options' do + IntercomRails.config.jwt.expiry = 24.hours + script_tag = ScriptTag.new( + user_details: { user_id: '1234' }, + jwt_enabled: true, + jwt_expiry: 1.hour + ) + + jwt = script_tag.intercom_settings[:intercom_user_jwt] + decoded_payload = JWT.decode(jwt, 'super-secret', true, { algorithm: 'HS256' })[0] + + expect(decoded_payload['exp']).to be_within(5).of(1.hour.from_now.to_i) + end + end end end