add API key authentication to Spotify admin endpoints

This commit is contained in:
2026-01-31 20:01:59 -05:00
parent 5251c7ef6d
commit 1afa68064e
3 changed files with 57 additions and 2 deletions

View File

@@ -1979,9 +1979,10 @@ public class JellyfinController : ControllerBase
/// <summary>
/// Manual trigger endpoint to force fetch Spotify missing tracks.
/// GET /spotify/sync
/// GET /spotify/sync?api_key=YOUR_KEY
/// </summary>
[HttpGet("spotify/sync")]
[ServiceFilter(typeof(ApiKeyAuthFilter))]
public async Task<IActionResult> TriggerSpotifySync()
{
if (!_spotifySettings.Enabled)
@@ -2110,9 +2111,10 @@ public class JellyfinController : ControllerBase
/// <summary>
/// Clear Spotify playlist cache to force re-matching.
/// GET /spotify/clear-cache
/// GET /spotify/clear-cache?api_key=YOUR_KEY
/// </summary>
[HttpGet("spotify/clear-cache")]
[ServiceFilter(typeof(ApiKeyAuthFilter))]
public async Task<IActionResult> ClearSpotifyCache()
{
if (!_spotifySettings.Enabled)

View File

@@ -0,0 +1,52 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Options;
using allstarr.Models.Settings;
namespace allstarr.Filters;
/// <summary>
/// Simple API key authentication filter for admin endpoints.
/// Validates against Jellyfin API key via query parameter or header.
/// </summary>
public class ApiKeyAuthFilter : IAsyncActionFilter
{
private readonly JellyfinSettings _settings;
private readonly ILogger<ApiKeyAuthFilter> _logger;
public ApiKeyAuthFilter(
IOptions<JellyfinSettings> settings,
ILogger<ApiKeyAuthFilter> logger)
{
_settings = settings.Value;
_logger = logger;
}
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
var request = context.HttpContext.Request;
// Extract API key from query parameter or header
var apiKey = request.Query["api_key"].FirstOrDefault()
?? request.Headers["X-Api-Key"].FirstOrDefault()
?? request.Headers["X-Emby-Token"].FirstOrDefault();
// Validate API key
if (string.IsNullOrEmpty(apiKey) || !string.Equals(apiKey, _settings.ApiKey, StringComparison.Ordinal))
{
_logger.LogWarning("Unauthorized access attempt to {Path} from {IP}",
request.Path,
context.HttpContext.Connection.RemoteIpAddress);
context.Result = new UnauthorizedObjectResult(new
{
error = "Unauthorized",
message = "Valid API key required. Provide via ?api_key=YOUR_KEY or X-Api-Key header."
});
return;
}
_logger.LogDebug("API key authentication successful for {Path}", request.Path);
await next();
}
}

View File

@@ -174,6 +174,7 @@ if (backendType == BackendType.Jellyfin)
builder.Services.AddSingleton<JellyfinModelMapper>();
builder.Services.AddScoped<JellyfinProxyService>();
builder.Services.AddScoped<JellyfinAuthFilter>();
builder.Services.AddScoped<allstarr.Filters.ApiKeyAuthFilter>();
}
else
{