backend-service/docs/JITSI_JWT_AUTHENTICATION.md
ats-tech25 04f2d02afc docs(api comprehensive API documentation for attune Heart Therapy
Add detailed API:
- Complete API documentation for In Format Usage flow diagrams for authentication and booking processes
- Comprehensive endpoint descriptions with request/response examples
- Detailed authentication and booking flow explanations
- Structured documentation for health checks, authentication, and booking endpoints
-: - Includes JWT authentication details
usage
- Provides clear API usage patterns for users and clients and administrators
system interactions
- Enhances project documentation with provides clear, structured API reference
- Improves developer and user understanding of system capabilities
2025-11-07 19:22:46 +00:00

8.3 KiB

Jitsi JWT Authentication Implementation

Overview

The system now uses JWT (JSON Web Token) authentication for Jitsi meetings, providing proper moderator privileges and secure meeting access. This replaces the previous URL parameter approach with industry-standard JWT tokens.

How It Works

JWT Token Structure

Each meeting link includes a JWT token that contains:

{
  "context": {
    "user": {
      "name": "John Doe",
      "email": "john@example.com",
      "moderator": "true"  // "true" for admin, "false" for regular users
    }
  },
  "room": "booking-123-1234567890-abc123",
  "aud": "jitsi",
  "iss": "your-app-id",
  "sub": "your-jitsi-domain.com",
  "exp": 1234567890  // 24 hour expiry
}

Meeting URL Format

With JWT (Recommended):

https://meet.jit.si/booking-123-abc?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Fallback (No JWT configured):

https://meet.jit.si/booking-123-abc#userInfo.displayName="John Doe"

Configuration

Option 1: Public Jitsi (meet.jit.si)

For testing or using public Jitsi servers, leave JWT configuration empty:

JITSI_BASE_URL=https://meet.jit.si
JITSI_API_KEY=
JITSI_APP_ID=

Note: Public Jitsi doesn't enforce JWT authentication, so the system will fall back to URL parameters. Moderator privileges won't work properly on public servers.

Option 2: Self-Hosted Jitsi with JWT

For production with proper moderator control, configure your self-hosted Jitsi:

JITSI_BASE_URL=https://meet.yourdomain.com
JITSI_API_KEY=your_jwt_secret_key_here
JITSI_APP_ID=your_app_id_here

Setting Up Self-Hosted Jitsi with JWT

1. Install Jitsi Meet

Follow the official guide: https://jitsi.github.io/handbook/docs/devops-guide/devops-guide-quickstart

2. Enable JWT Authentication

Edit /etc/prosody/conf.avail/yourdomain.com.cfg.lua:

VirtualHost "yourdomain.com"
    authentication = "token"
    app_id = "your_app_id"
    app_secret = "your_jwt_secret_key"
    allow_empty_token = false

3. Configure Jicofo

Edit /etc/jitsi/jicofo/sip-communicator.properties:

org.jitsi.jicofo.auth.URL=XMPP:yourdomain.com

4. Restart Services

systemctl restart prosody
systemctl restart jicofo
systemctl restart jitsi-videobridge2

5. Update Your .env File

JITSI_BASE_URL=https://meet.yourdomain.com
JITSI_API_KEY=your_jwt_secret_key
JITSI_APP_ID=your_app_id

API Response Examples

GET /api/bookings

{
  "bookings": [
    {
      "id": 123,
      "jitsi_room_id": "booking-123-1234567890-abc123",
      "jitsi_room_url": "https://meet.jit.si/booking-123-1234567890-abc123",
      "personalized_meeting_url": "https://meet.jit.si/booking-123-1234567890-abc123?jwt=eyJhbGc..."
    }
  ]
}

GET /api/admin/bookings

{
  "bookings": [
    {
      "id": 123,
      "jitsi_room_id": "booking-123-1234567890-abc123",
      "jitsi_room_url": "https://meet.jit.si/booking-123-1234567890-abc123",
      "admin_meeting_url": "https://meet.jit.si/booking-123-1234567890-abc123?jwt=eyJhbGc..."
    }
  ]
}
{
  "booking_id": 123,
  "meeting_url": "https://meet.jit.si/booking-123-1234567890-abc123?jwt=eyJhbGc...",
  "display_name": "John Doe",
  "is_admin": false
}

User vs Admin Differences

Regular User Token

{
  "context": {
    "user": {
      "name": "John Doe",
      "email": "john@example.com",
      "moderator": "false"
    }
  }
}

Permissions:

  • Can join meeting
  • Can share screen
  • Can mute/unmute themselves
  • Cannot kick participants
  • Cannot end meeting for all

Admin User Token

{
  "context": {
    "user": {
      "name": "Dr. Smith",
      "email": "dr.smith@example.com",
      "moderator": "true"
    }
  }
}

Permissions:

  • All regular user permissions
  • Can kick participants
  • Can mute other participants
  • Can end meeting for all
  • Can start/stop recording (if configured)
  • Can enable/disable lobby

Email Notifications

All email notifications now include JWT-authenticated links:

Meeting Info Email

<a href="https://meet.jit.si/booking-123?jwt=eyJhbGc...">Join Meeting</a>

Reminder Email

<a href="https://meet.jit.si/booking-123?jwt=eyJhbGc...">Join Meeting</a>

Security Features

Token Expiration

  • Tokens expire after 24 hours
  • Users must request a new link after expiration
  • Prevents unauthorized access to old meetings

Moderator Control

  • Only users with is_admin: true get moderator tokens
  • Moderator status is cryptographically signed in JWT
  • Cannot be tampered with by users

Room Isolation

  • Each booking gets a unique room ID
  • Room name is embedded in JWT
  • Token only works for the specified room

Testing

Test JWT Generation

# Start the server
go run cmd/server/main.go

# Get a meeting link as regular user
curl -H "Authorization: Bearer <user_token>" \
  http://localhost:8080/api/meetings/123/link

# Get a meeting link as admin
curl -H "Authorization: Bearer <admin_token>" \
  http://localhost:8080/api/admin/bookings

Verify JWT Token

Use https://jwt.io to decode and verify your tokens:

  1. Copy the JWT from the meeting URL
  2. Paste into jwt.io debugger
  3. Verify the payload contains correct user info
  4. Check moderator field is "true" for admins

Test Moderator Privileges

  1. Create two bookings
  2. Join one as regular user
  3. Join another as admin
  4. Verify admin can:
    • See moderator controls
    • Kick participants
    • End meeting for all

Troubleshooting

Issue: "Room locked" or "Authentication failed"

Cause: JWT not configured or invalid

Solution:

  1. Check JITSI_API_KEY and JITSI_APP_ID are set
  2. Verify they match your Jitsi server configuration
  3. Ensure Jitsi server has JWT authentication enabled

Issue: Admin doesn't have moderator privileges

Cause: JWT not being used or moderator claim not set

Solution:

  1. Verify JITSI_API_KEY is configured
  2. Check admin user has is_admin: true in database
  3. Decode JWT token and verify moderator: "true"

Issue: Token expired error

Cause: JWT token older than 24 hours

Solution:

  1. Request a new meeting link
  2. Tokens are generated fresh on each API call
  3. Consider reducing expiry time if needed

Issue: Fallback to URL parameters

Cause: JWT configuration missing

Solution:

  1. This is expected behavior when JWT not configured
  2. For production, configure JWT authentication
  3. URL parameters work but don't enforce moderator privileges

Migration from URL Parameters

Before (URL Parameters)

https://meet.jit.si/room#userInfo.displayName="John"&config.startWithAudioMuted=false

Problems:

  • No real moderator enforcement
  • Anyone can modify URL parameters
  • No security

After (JWT Authentication)

https://meet.jit.si/room?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Benefits:

  • Cryptographically signed tokens
  • True moderator enforcement
  • Secure and tamper-proof
  • Industry standard

Best Practices

  1. Use Self-Hosted Jitsi: For production, always use self-hosted Jitsi with JWT
  2. Rotate Secrets: Regularly rotate your JITSI_API_KEY
  3. Monitor Token Usage: Log token generation for audit purposes
  4. Set Appropriate Expiry: 24 hours is reasonable, adjust based on needs
  5. Test Moderator Controls: Regularly verify admin privileges work correctly

Advanced Configuration

Custom Token Expiry

Edit internal/services/jitsi_service.go:

ExpiresAt: jwt.NewNumericDate(time.Now().Add(2 * time.Hour)), // 2 hour expiry

Additional JWT Claims

Add custom claims to the JWT:

type JitsiClaims struct {
    Context JitsiContext `json:"context"`
    Room    string       `json:"room"`
    Avatar  string       `json:"avatar,omitempty"`  // User avatar URL
    jwt.RegisteredClaims
}

Multiple Jitsi Servers

Support multiple Jitsi servers by environment:

func (j *jitsiService) getJitsiURL() string {
    if os.Getenv("ENVIRONMENT") == "production" {
        return "https://meet.production.com"
    }
    return "https://meet.staging.com"
}

References