# WebSocket Authentication Guide

## Overview

WebSocket connections to Jellyfin servers require authentication. This guide explains how to properly authenticate WebSocket connections using API tokens.

## Authentication Methods

### 1. Query String Parameter (Recommended for WebSocket)

The simplest and most compatible method for WebSocket connections.

**URL Format:**
```
ws://jellyfin-server:8096/socket?api_key=YOUR_API_TOKEN
wss://jellyfin-server:8096/socket?api_key=YOUR_API_TOKEN  (for HTTPS)
```

**JavaScript Example:**
```javascript
const token = "YOUR_API_KEY";
const ws = new WebSocket(`ws://jellyfin-server:8096/socket?api_key=${token}`);

ws.onopen = function(event) {
	console.log("WebSocket connection established with authentication");
};

ws.onerror = function(event) {
	console.error("WebSocket error:", event);
};

ws.onmessage = function(event) {
	const message = JSON.parse(event.data);
	console.log("Received message:", message);
};

ws.onclose = function(event) {
	console.log("WebSocket connection closed");
};
```

**Python Example:**
```python
import asyncio
import websockets
import json

async def connect_with_token():
	token = "YOUR_API_KEY"
	uri = f"ws://jellyfin-server:8096/socket?api_key={token}"

	async with websockets.connect(uri) as websocket:
		print("Connected to Jellyfin WebSocket")

		# Receive messages
		async for message in websocket:
			data = json.loads(message)
			print(f"Received: {data}")

asyncio.run(connect_with_token())
```

**C# Example:**
```csharp
using System;
using System.Net.WebSockets;
using System.Threading;
using System.Threading.Tasks;

public class JellyfinWebSocketClient
{
	public async Task ConnectAsync(string serverUrl, string token)
	{
		var uri = new Uri($"ws://{serverUrl}:8096/socket?api_key={token}");

		using (var client = new ClientWebSocket())
		{
			await client.ConnectAsync(uri, CancellationToken.None);

			Console.WriteLine("Connected to Jellyfin WebSocket");

			// Receive messages
			var buffer = new byte[1024 * 4];
			while (client.State == WebSocketState.Open)
			{
				var result = await client.ReceiveAsync(
					new ArraySegment<byte>(buffer),
					CancellationToken.None);

				if (result.MessageType == WebSocketMessageType.Text)
				{
					var message = System.Text.Encoding.UTF8.GetString(
						buffer, 0, result.Count);
					Console.WriteLine($"Received: {message}");
				}
			}
		}
	}
}
```

### 2. Authorization Header (Alternative)

For advanced use cases, you can also use the Authorization header.

**Header Format:**
```
Authorization: MediaBrowser Device="ClientName", DeviceId="unique-id", Version="1.0", Token="YOUR_API_TOKEN"
```

**Note:** Some WebSocket implementations may not support custom headers during the upgrade handshake. Query parameters are recommended.

## Obtaining an API Token

### Via Server UI
1. Navigate to your Jellyfin server dashboard
2. Go to Settings → API Keys (or similar, depending on version)
3. Create a new API key
4. Copy the token to use in your WebSocket connection

### Programmatically
Use the REST API to create API keys:
```bash
curl -X POST "http://jellyfin-server:8096/Auth/Keys" \
  -H "Authorization: MediaBrowser Token=existing_token" \
  -H "Content-Type: application/json" \
  -d '{"AppName": "My WebSocket Client"}'
```

## Common Issues

### Connection Refused / 401 Unauthorized
- Verify the API token is correct
- Ensure the token hasn't expired
- Check that the WebSocket endpoint path is correct (`/socket`)

### Token Not Found
- Verify the query parameter is URL-encoded properly
- Ensure the parameter name is correct: `api_key` (lowercase)
- Check server logs for authentication errors

### WebSocket Connection Fails Immediately
- Confirm the server is reachable
- Check firewall rules allow WebSocket connections
- Try with `wss://` (secure WebSocket) if using HTTPS

## Server Configuration

The server automatically extracts tokens from:
1. Authorization header (MediaBrowser Token parameter)
2. Query string `api_key` parameter
3. Query string `ApiKey` parameter
4. Legacy headers (if enabled in config)

No special server configuration is required for WebSocket authentication to work.

## Security Considerations

- Always use `wss://` (secure WebSocket) when connecting over untrusted networks
- Keep API tokens secure and rotate them periodically
- Use separate tokens for different clients/applications
- Consider implementing token expiration in your server configuration

## See Also

- [Jellyfin API Documentation](https://api.jellyfin.org/)
- [WebSocket Protocol (RFC 6455)](https://tools.ietf.org/html/rfc6455)
