e81c127514
- Add JSON-based config loading with XML fallback for DB and library options - Implement LibraryOptionsRepository with EF Core, migrations, and entity - Update CollectionFolder to use DB-backed options with XML fallback/backfill - Register repository in DI and initialize at startup - Use EF execution strategy for transactional DB operations - Suppress code analysis warnings in .csproj and test files - Add DATABASE_MIGRATION.md, LIBRARY_OPTIONS_DB_DESIGN.md, and WEBSOCKET_AUTHENTICATION.md - Add database.json.example and improve migration docs - Add tests for JSON config loader and update test naming warnings
168 lines
4.5 KiB
Markdown
168 lines
4.5 KiB
Markdown
# 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)
|