mirror of
				https://github.com/lingble/chatwoot.git
				synced 2025-10-31 02:57:57 +00:00 
			
		
		
		
	feat: Add support for customizing expiry of widget token (#12446)
This PR is part of https://github.com/chatwoot/chatwoot/pull/12259. It adds a default expiry of 180 days for tokens issued on the widget. The expiry can be customized based on customer requests and internal security requirements. Co-authored-by: Balasaheb Dubale <bdubale@entrata.com>
This commit is contained in:
		| @@ -1,8 +1,10 @@ | ||||
| class Widget::TokenService | ||||
|   DEFAULT_EXPIRY_DAYS = 180 | ||||
|  | ||||
|   pattr_initialize [:payload, :token] | ||||
|  | ||||
|   def generate_token | ||||
|     JWT.encode payload, secret_key, 'HS256' | ||||
|     JWT.encode payload_with_expiry, secret_key, 'HS256' | ||||
|   end | ||||
|  | ||||
|   def decode_token | ||||
| @@ -15,6 +17,24 @@ class Widget::TokenService | ||||
|  | ||||
|   private | ||||
|  | ||||
|   def payload_with_expiry | ||||
|     payload.merge(exp: exp, iat: iat) | ||||
|   end | ||||
|  | ||||
|   def iat | ||||
|     Time.zone.now.to_i | ||||
|   end | ||||
|  | ||||
|   def exp | ||||
|     iat + expire_in.days.to_i | ||||
|   end | ||||
|  | ||||
|   def expire_in | ||||
|     # Value is stored in days, defaulting to 6 months (180 days) | ||||
|     token_expiry_value = InstallationConfig.find_by(name: 'WIDGET_TOKEN_EXPIRY')&.value | ||||
|     (token_expiry_value.presence || DEFAULT_EXPIRY_DAYS).to_i | ||||
|   end | ||||
|  | ||||
|   def secret_key | ||||
|     Rails.application.secret_key_base | ||||
|   end | ||||
|   | ||||
| @@ -439,3 +439,11 @@ | ||||
|   locked: false | ||||
|   description: 'Zone ID for the Cloudflare domain' | ||||
| ## ------ End of Configs added for Cloudflare ------ ## | ||||
|  | ||||
| ## ------ Customizations for Customers ------ ## | ||||
| - name: WIDGET_TOKEN_EXPIRY | ||||
|   display_title: 'Widget Token Expiry' | ||||
|   value: 180 | ||||
|   locked: false | ||||
|   description: 'Token expiry in days' | ||||
| ## ------ End of Customizations for Customers ------ ## | ||||
|   | ||||
							
								
								
									
										42
									
								
								spec/services/widget/token_service_expiry_spec.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								spec/services/widget/token_service_expiry_spec.rb
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,42 @@ | ||||
| require 'rails_helper' | ||||
|  | ||||
| RSpec.describe Widget::TokenService, type: :service do | ||||
|   describe 'token expiry configuration' do | ||||
|     let(:service) { described_class.new(payload: {}) } | ||||
|  | ||||
|     before do | ||||
|       # Clear any existing configs to ensure test isolation | ||||
|       InstallationConfig.where(name: 'WIDGET_TOKEN_EXPIRY').destroy_all | ||||
|     end | ||||
|  | ||||
|     context 'with valid configuration' do | ||||
|       before do | ||||
|         create(:installation_config, name: 'WIDGET_TOKEN_EXPIRY', value: '30') | ||||
|       end | ||||
|  | ||||
|       it 'uses the configured value for token expiry' do | ||||
|         freeze_time do | ||||
|           token = service.generate_token | ||||
|           decoded = JWT.decode(token, Rails.application.secret_key_base, true, algorithm: 'HS256').first | ||||
|           expect(decoded['iat']).to eq(Time.now.to_i) | ||||
|           expect(decoded['exp']).to eq(30.days.from_now.to_i) | ||||
|         end | ||||
|       end | ||||
|     end | ||||
|  | ||||
|     context 'with empty configuration' do | ||||
|       before do | ||||
|         create(:installation_config, name: 'WIDGET_TOKEN_EXPIRY', value: '') | ||||
|       end | ||||
|  | ||||
|       it 'uses the default expiry' do | ||||
|         freeze_time do | ||||
|           token = service.generate_token | ||||
|           decoded = JWT.decode(token, Rails.application.secret_key_base, true, algorithm: 'HS256').first | ||||
|           expect(decoded['iat']).to eq(Time.now.to_i) | ||||
|           expect(decoded['exp']).to eq(180.days.from_now.to_i) | ||||
|         end | ||||
|       end | ||||
|     end | ||||
|   end | ||||
| end | ||||
		Reference in New Issue
	
	Block a user
	 Pranav
					Pranav