General08 troubleshooting
Authentication Issues Troubleshooting
This guide covers common authentication problems in the Kulcare API backend and their solutions.
Common Authentication Issues
JWT Token Problems
Issue: "JWT::DecodeError: Invalid token"
Symptoms:
- Users getting "Invalid token" errors
- API returns 401 Unauthorized
- Token validation fails
Diagnosis:
# Rails console debugging
token = "your_jwt_token_here"
decoded_token = TokenIssuer.decode_token(token)
if decoded_token.nil?
puts "Token is invalid or corrupted"
else
puts "Token payload: #{decoded_token}"
puts "Expires at: #{Time.at(decoded_token['exp'])}"
puts "User ID: #{decoded_token['user_id']}"
endCommon Causes:
- Secret Key Mismatch: Different secret keys between environments
- Token Corruption: Network issues or client-side storage problems
- Algorithm Mismatch: JWT algorithm not matching server configuration
Solutions:
# 1. Verify secret key configuration
Rails.application.credentials.secret_key_base
# 2. Check token generation
user = User.find(123)
test_token = TokenIssuer.issue_token(user_id: user.id)
decoded = TokenIssuer.decode_token(test_token)
puts "Test token valid: #{!decoded.nil?}"
# 3. Review client token storage
# Ensure client apps store tokens properly without modificationIssue: "Token expired"
Symptoms:
- Valid tokens getting expired errors
- Users forced to login frequently
- Refresh token flow not working
Diagnosis:
# Check token expiration settings
token = TokenIssuer.decode_token(expired_token)
if token
exp_time = Time.at(token['exp'])
puts "Token expired at: #{exp_time}"
puts "Current time: #{Time.current}"
puts "Expired #{Time.current - exp_time} seconds ago"
end
# Check refresh token status
refresh_token = RefreshToken.find_by(token: encrypted_refresh_token)
puts "Refresh token exists: #{refresh_token.present?}"
puts "Refresh token expired: #{refresh_token&.expired?}"Solutions:
# 1. Adjust token expiration time
# In TokenIssuer service
def self.issue_token(payload, expiration = 24.hours.from_now) # Increase if needed
# token generation logic
end
# 2. Implement proper refresh token flow
# Ensure clients implement automatic token refresh
POST /auth/refresh
{
"refresh_token": "encrypted_refresh_token",
"user_id": 123
}
# 3. Check refresh token cleanup
# Remove expired refresh tokens
RefreshToken.where('expires_at < ?', Time.current).destroy_allMulti-Profile Authentication Issues
Issue: Profile Access Denied
Symptoms:
- Users can't access specific profiles
- "Profile not found or not accessible" errors
- Wrong user_account_id in requests
Diagnosis:
# Check user's available profiles
user = User.find(123)
profiles = user.user_accounts.includes(:account, :role)
profiles.each do |ua|
puts "Profile ID: #{ua.id}"
puts "Account Type: #{ua.account.name}"
puts "Role: #{ua.role.name}"
puts "Profile ID: #{ua.profile_id}"
puts "Deleted: #{ua.deleted}"
puts "---"
end
# Verify specific profile access
user_account_id = 456
profile = user.user_accounts.find_by(id: user_account_id)
puts "Profile exists: #{profile.present?}"
puts "Profile deleted: #{profile&.deleted?}"Solutions:
# 1. Check profile deletion status
UserAccount.where(user_id: user_id, deleted: true).update_all(deleted: false)
# 2. Verify profile creation
# Ensure profiles are created during registration
user.create_profile # Method in User model
# 3. Fix missing clinic-doctor relationships
doctor = user.doctor_profiles.first
if doctor && doctor.clinics.empty?
# Create default clinic for doctor
clinic = Clinic.create!(name: "#{doctor.name} Clinic", ...)
# Link doctor to clinic
endIssue: Profile Context Problems
Symptoms:
- API calls returning wrong clinic/doctor data
- Permission errors for valid operations
- Data not filtered by current profile
Diagnosis:
# Check current profile context in controller
current_profile = current_user.user_accounts.find_by(id: params[:user_account_id])
puts "Current profile: #{current_profile&.account&.name}"
puts "Profile clinic ID: #{current_profile&.profile_id}" if current_profile&.account&.name == 'clinic'
# Verify data access permissions
case current_profile&.account&.name
when 'clinic'
clinic = Clinic.find(current_profile.profile_id)
puts "Clinic patients count: #{clinic.clinic_patients.count}"
when 'doctor'
doctor = Doctor.find(current_profile.profile_id)
puts "Doctor clinics: #{doctor.clinics.pluck(:name)}"
endSolutions:
# 1. Ensure user_account_id is passed in requests
# Frontend should include user_account_id in API calls
# Backend should validate and use this for context
# 2. Implement proper profile authorization
class ApplicationController
before_action :set_current_profile
private
def set_current_profile
if params[:user_account_id].present?
@current_profile = current_user.user_accounts.find_by(id: params[:user_account_id])
unless @current_profile
render json: { error: 'Profile not found' }, status: :forbidden
return
end
end
end
end
# 3. Use profile context in queries
# Always filter data by current profile context
appointments = current_clinic.appointments # Not all appointmentsOTP Verification Issues
Issue: OTP Not Delivered
Symptoms:
- Users not receiving verification codes
- SMS/WhatsApp delivery failures
- OTP timeout errors
Diagnosis:
# Check recent OTP messages
user = User.find_by(phone_number: '919876543210')
puts "User verification status: #{user&.verified?}"
puts "Last verification code sent: #{user&.verification_code_sent_at}"
# Check message logs
recent_messages = MsgLog.where(phone_number: '919876543210')
.where('created_at > ?', 1.hour.ago)
recent_messages.each do |msg|
puts "Type: #{msg.msg_type}, Status: #{msg.msg_status}, Text: #{msg.msg_text[0..50]}"
end
# Check SMS service health
begin
response = HTTParty.post('https://api.msg91.com/api/v2/sendsms', {
# test message
})
puts "MSG91 API Status: #{response.code}"
rescue => e
puts "MSG91 API Error: #{e.message}"
endSolutions:
# 1. Resend verification code manually
user.send_verification_code
# 2. Check SMS provider configuration
# Verify MSG91/Twilio credentials
Rails.application.credentials.msg91_auth_key
Rails.application.credentials.twilio_account_sid
# 3. Test with different phone number format
# Ensure proper country code formatting
phone = "+91#{phone_number}" unless phone_number.start_with?('+')Issue: Invalid OTP Error
Symptoms:
- Correct OTP showing as invalid
- OTP expiration issues
- Case sensitivity problems
Diagnosis:
# Check OTP details
user = User.find_by(phone_number: '919876543210')
puts "Stored OTP: #{user.verification_code}"
puts "OTP sent at: #{user.verification_code_sent_at}"
puts "Current time: #{Time.current}"
puts "Minutes since sent: #{(Time.current - user.verification_code_sent_at) / 60}"
# Test OTP verification
test_code = "12345"
puts "OTP valid: #{user.verify_code(test_code)}"Solutions:
# 1. Check OTP expiration window
def verify_code(code)
return false if verification_code.blank?
return false if verification_code_sent_at < 10.minutes.ago # Adjust window
verification_code == code.to_s # Ensure string comparison
end
# 2. Implement case-insensitive comparison if needed
verification_code.downcase == code.to_s.downcase
# 3. Add OTP retry mechanism
def resend_verification_code
return false if verification_code_sent_at > 1.minute.ago # Rate limiting
send_verification_code
endSession Management Issues
Issue: User Session Expired
Symptoms:
- Frequent forced logouts
- Session timeout errors
- Device registration problems
Diagnosis:
# Check user devices
user = User.find(123)
devices = user.devices.includes(:refresh_tokens)
devices.each do |device|
puts "Device: #{device.device_name} (#{device.platform})"
puts "Last active: #{device.last_active_at}"
puts "Active refresh tokens: #{device.refresh_tokens.active.count}"
end
# Check session duration settings
puts "Token expiration: #{24.hours.to_i} seconds"
puts "Refresh token expiration: #{30.days.to_i} seconds"Solutions:
# 1. Update device activity tracking
class ApplicationController
after_action :update_device_activity
private
def update_device_activity
if current_user && device_identifier.present?
device = current_user.devices.find_by(device_id: device_identifier)
device&.update_activity!
end
end
end
# 2. Clean up expired tokens
RefreshToken.where('expires_at < ?', Time.current).destroy_all
# 3. Extend session duration if needed
# Adjust expiration times in TokenIssuerSocial Authentication Issues
Issue: OAuth Connection Failures
Symptoms:
- Social login not working
- OAuth provider errors
- Missing user information
Diagnosis:
# Check OAuth configuration
puts "Facebook App ID: #{Rails.application.credentials.facebook_app_id}"
puts "Google Client ID: #{Rails.application.credentials.google_client_id}"
# Check existing social connections
user = User.find(123)
auth_services = user.auth_services
auth_services.each do |auth_service|
puts "Provider: #{auth_service.auth_type}"
puts "UID: #{auth_service.uid}"
puts "Created: #{auth_service.created_at}"
endSolutions:
# 1. Verify OAuth app configuration
# Check redirect URLs in provider dashboards
# Ensure client IDs and secrets are correct
# 2. Handle OAuth errors gracefully
begin
auth_service = AuthService.create!(oauth_params)
rescue ActiveRecord::RecordInvalid => e
puts "OAuth error: #{e.message}"
# Handle duplicate account scenario
end
# 3. Test OAuth flow manually
# Use provider's OAuth playground to test tokensPassword Reset Issues
Issue: Reset Password Not Working
Symptoms:
- Reset password emails not sent
- Invalid reset tokens
- Reset links not working
Diagnosis:
# Check password reset request
user = User.find_by(email: 'user@example.com')
puts "User found: #{user.present?}"
puts "Reset token: #{user&.reset_password_token}"
puts "Reset sent at: #{user&.reset_password_sent_at}"
# Check email delivery
# Review ActionMailer logs for delivery statusSolutions:
# 1. Resend password reset manually
user.send_reset_password_instructions!
# 2. Check email configuration
# Verify SMTP settings in config/environments/production.rb
config.action_mailer.smtp_settings = {
# SMTP configuration
}
# 3. Implement backup reset mechanism
# SMS-based password reset for users without emailPrevention Strategies
Monitoring Authentication Health
# Authentication health check endpoint
def auth_health_check
{
total_active_sessions: RefreshToken.active.count,
failed_logins_last_hour: login_failures_count,
otp_delivery_rate: otp_success_rate,
token_expiration_issues: expired_token_count,
multi_profile_errors: profile_access_errors
}
endAutomated Testing
# Authentication system tests
RSpec.describe 'Authentication System' do
describe 'JWT Token Flow' do
it 'issues and validates tokens correctly' do
user = create(:user, :verified)
token = TokenIssuer.issue_token(user_id: user.id)
decoded = TokenIssuer.decode_token(token)
expect(decoded['user_id']).to eq(user.id)
expect(decoded['exp']).to be > Time.current.to_i
end
end
describe 'Multi-Profile Access' do
it 'allows access to user profiles' do
user = create(:user, :with_clinic_profile)
profile = user.user_accounts.first
expect(profile).to be_present
expect(profile.deleted).to be_falsey
end
end
endSecurity Best Practices
Token Security
- Use strong secret keys for JWT signing
- Implement proper token rotation
- Monitor for token reuse attacks
- Set appropriate expiration times
Session Security
- Implement device fingerprinting
- Monitor for concurrent sessions
- Log suspicious authentication patterns
- Implement account lockout for failed attempts
Multi-Profile Security
- Validate profile access on every request
- Audit profile switching activities
- Implement role-based permissions
- Monitor cross-profile data access
Quick Fixes
Emergency Authentication Reset
# Rails console commands for emergency fixes
# Reset user verification status
User.find_by(phone_number: '919876543210').update!(verified: true)
# Clear expired tokens
RefreshToken.where('expires_at < ?', Time.current).destroy_all
# Regenerate user profile
user = User.find(123)
user.create_profile if user.user_accounts.empty?
# Reset OAuth connections
user.auth_services.destroy_all # User will need to reconnectDatabase Fixes
-- SQL commands for direct database fixes
-- Fix deleted user accounts
UPDATE user_accounts SET deleted = false WHERE user_id = 123 AND deleted = true;
-- Reset OTP codes that are stuck
UPDATE users SET verification_code = NULL, verification_code_sent_at = NULL
WHERE verification_code_sent_at < NOW() - INTERVAL '1 hour';
-- Clean up orphaned refresh tokens
DELETE FROM refresh_tokens WHERE expires_at < NOW();Related Documentation
- Authentication System - Complete authentication architecture
- API Reference - Authentication API endpoints
- Security Guide - Security-related troubleshooting
- Integration Issues - Third-party authentication problems