Skip to content

Commit e701491

Browse files
authored
Optionally support expiry of JWTs (#361)
1 parent c2be338 commit e701491

File tree

3 files changed

+51
-7
lines changed

3 files changed

+51
-7
lines changed

lib/intercom-rails/config.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ def self.company_association=(*)
145145

146146
config_group :jwt do
147147
config_accessor :enabled
148+
config_accessor :expiry
148149
config_accessor :signed_user_fields do |value|
149150
unless value.nil? || (value.kind_of?(Array) && value.all? { |v| v.kind_of?(Symbol) || v.kind_of?(String) })
150151
raise ArgumentError, "jwt.signed_user_fields must be an array of symbols or strings"

lib/intercom-rails/script_tag.rb

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ class ScriptTag
1818
include ::ActionView::Helpers::TagHelper
1919

2020
attr_reader :user_details, :company_details, :show_everywhere, :session_duration
21-
attr_accessor :secret, :widget_options, :controller, :nonce, :encrypted_mode_enabled, :encrypted_mode, :jwt_enabled
21+
attr_accessor :secret, :widget_options, :controller, :nonce, :encrypted_mode_enabled, :encrypted_mode, :jwt_enabled, :jwt_expiry
2222

2323
def initialize(options = {})
2424
self.secret = options[:secret] || Config.api_secret
@@ -27,6 +27,7 @@ def initialize(options = {})
2727
@show_everywhere = options[:show_everywhere]
2828
@session_duration = session_duration_from_config
2929
self.jwt_enabled = options[:jwt_enabled] || Config.jwt.enabled
30+
self.jwt_expiry = options[:jwt_expiry] || Config.jwt.expiry
3031

3132
initial_user_details = if options[:find_current_user_details]
3233
find_current_user_details
@@ -124,10 +125,11 @@ def intercom_javascript
124125
def generate_jwt
125126
return nil unless user_details[:user_id].present?
126127

127-
payload = {
128-
user_id: user_details[:user_id].to_s,
129-
exp: 24.hours.from_now.to_i
130-
}
128+
payload = { user_id: user_details[:user_id].to_s }
129+
130+
if jwt_expiry
131+
payload[:exp] = jwt_expiry.from_now.to_i
132+
end
131133

132134
if Config.jwt.signed_user_fields.present?
133135
Config.jwt.signed_user_fields.each do |field|

spec/script_tag_spec.rb

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,7 @@ def user
332332
expect(script_tag.intercom_settings[:user_hash]).to be_nil
333333
end
334334

335-
it 'generates a valid JWT with correct payload' do
335+
it 'generates a valid JWT with the correct user_id' do
336336
user_id = '1234'
337337
script_tag = ScriptTag.new(
338338
user_details: { user_id: user_id },
@@ -343,7 +343,6 @@ def user
343343
decoded_payload = JWT.decode(jwt, 'super-secret', true, { algorithm: 'HS256' })[0]
344344

345345
expect(decoded_payload['user_id']).to eq(user_id)
346-
expect(decoded_payload['exp']).to be_within(5).of(24.hours.from_now.to_i)
347346
end
348347

349348
it 'does not generate JWT when user_id is missing' do
@@ -467,6 +466,48 @@ def user
467466
expect(script_tag.intercom_settings[:name]).to eq('Test User')
468467
end
469468
end
469+
470+
context 'JWT expiry' do
471+
it 'includes expiry when configured' do
472+
IntercomRails.config.jwt.expiry = 12.hours
473+
script_tag = ScriptTag.new(
474+
user_details: { user_id: '1234' },
475+
jwt_enabled: true
476+
)
477+
478+
jwt = script_tag.intercom_settings[:intercom_user_jwt]
479+
decoded_payload = JWT.decode(jwt, 'super-secret', true, { algorithm: 'HS256' })[0]
480+
481+
expect(decoded_payload['exp']).to be_within(5).of(12.hours.from_now.to_i)
482+
end
483+
484+
it 'omits expiry when not configured' do
485+
IntercomRails.config.jwt.expiry = nil
486+
script_tag = ScriptTag.new(
487+
user_details: { user_id: '1234' },
488+
jwt_enabled: true
489+
)
490+
491+
jwt = script_tag.intercom_settings[:intercom_user_jwt]
492+
decoded_payload = JWT.decode(jwt, 'super-secret', true, { algorithm: 'HS256' })[0]
493+
494+
expect(decoded_payload).not_to have_key('exp')
495+
end
496+
497+
it 'allows overriding expiry via options' do
498+
IntercomRails.config.jwt.expiry = 24.hours
499+
script_tag = ScriptTag.new(
500+
user_details: { user_id: '1234' },
501+
jwt_enabled: true,
502+
jwt_expiry: 1.hour
503+
)
504+
505+
jwt = script_tag.intercom_settings[:intercom_user_jwt]
506+
decoded_payload = JWT.decode(jwt, 'super-secret', true, { algorithm: 'HS256' })[0]
507+
508+
expect(decoded_payload['exp']).to be_within(5).of(1.hour.from_now.to_i)
509+
end
510+
end
470511
end
471512

472513
end

0 commit comments

Comments
 (0)