< Summary - Jellyfin

Information
Class: Jellyfin.Api.Auth.CustomAuthenticationHandler
Assembly: Jellyfin.Api
File(s): /srv/git/jellyfin/Jellyfin.Api/Auth/CustomAuthenticationHandler.cs
Line coverage
100%
Covered lines: 32
Uncovered lines: 0
Coverable lines: 32
Total lines: 90
Line coverage: 100%
Branch coverage
65%
Covered branches: 13
Total branches: 20
Branch coverage: 65%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Coverage history

Coverage history 0 25 50 75 100 5/16/2026 - 12:15:55 AM Line coverage: 96.8% (31/32) Branch coverage: 65% (13/20) Total lines: 9010/29/2026 - 12:17:11 AM Line coverage: 100% (32/32) Branch coverage: 65% (13/20) Total lines: 90 5/16/2026 - 12:15:55 AM Line coverage: 96.8% (31/32) Branch coverage: 65% (13/20) Total lines: 9010/29/2026 - 12:17:11 AM Line coverage: 100% (32/32) Branch coverage: 65% (13/20) Total lines: 90

Coverage delta

Coverage delta 4 -4

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
HandleAuthenticateAsync()65%202092.85%

File(s)

/srv/git/jellyfin/Jellyfin.Api/Auth/CustomAuthenticationHandler.cs

#LineLine coverage
 1using System.Globalization;
 2using System.Security.Claims;
 3using System.Text.Encodings.Web;
 4using System.Threading.Tasks;
 5using Jellyfin.Api.Constants;
 6using Jellyfin.Data;
 7using Jellyfin.Database.Implementations.Enums;
 8using MediaBrowser.Controller.Authentication;
 9using MediaBrowser.Controller.Net;
 10using Microsoft.AspNetCore.Authentication;
 11using Microsoft.Extensions.Logging;
 12using Microsoft.Extensions.Options;
 13
 14namespace Jellyfin.Api.Auth
 15{
 16    /// <summary>
 17    /// Custom authentication handler wrapping the legacy authentication.
 18    /// </summary>
 19    public class CustomAuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions>
 20    {
 21        private readonly IAuthService _authService;
 22        private readonly ILogger<CustomAuthenticationHandler> _logger;
 23
 24        /// <summary>
 25        /// Initializes a new instance of the <see cref="CustomAuthenticationHandler" /> class.
 26        /// </summary>
 27        /// <param name="authService">The jellyfin authentication service.</param>
 28        /// <param name="options">Options monitor.</param>
 29        /// <param name="logger">The logger.</param>
 30        /// <param name="encoder">The url encoder.</param>
 31        public CustomAuthenticationHandler(
 32            IAuthService authService,
 33            IOptionsMonitor<AuthenticationSchemeOptions> options,
 34            ILoggerFactory logger,
 35            UrlEncoder encoder)
 23336            : base(options, logger, encoder)
 37        {
 23338            _authService = authService;
 23339            _logger = logger.CreateLogger<CustomAuthenticationHandler>();
 23340        }
 41
 42        /// <inheritdoc />
 43        protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
 44        {
 45            try
 46            {
 23347                var authorizationInfo = await _authService.Authenticate(Request).ConfigureAwait(false);
 23148                if (!authorizationInfo.HasToken)
 49                {
 8250                    return AuthenticateResult.NoResult();
 51                }
 52
 14953                var role = UserRoles.User;
 14954                if (authorizationInfo.IsApiKey
 14955                    || (authorizationInfo.User?.HasPermission(PermissionKind.IsAdministrator) ?? false))
 56                {
 14557                    role = UserRoles.Administrator;
 58                }
 59
 14960                var claims = new[]
 14961                {
 14962                    new Claim(ClaimTypes.Name, authorizationInfo.User?.Username ?? string.Empty),
 14963                    new Claim(ClaimTypes.Role, role),
 14964                    new Claim(InternalClaimTypes.UserId, authorizationInfo.UserId.ToString("N", CultureInfo.InvariantCul
 14965                    new Claim(InternalClaimTypes.DeviceId, authorizationInfo.DeviceId ?? string.Empty),
 14966                    new Claim(InternalClaimTypes.Device, authorizationInfo.Device ?? string.Empty),
 14967                    new Claim(InternalClaimTypes.Client, authorizationInfo.Client ?? string.Empty),
 14968                    new Claim(InternalClaimTypes.Version, authorizationInfo.Version ?? string.Empty),
 14969                    new Claim(InternalClaimTypes.Token, authorizationInfo.Token),
 14970                    new Claim(InternalClaimTypes.IsApiKey, authorizationInfo.IsApiKey.ToString(CultureInfo.InvariantCult
 14971                };
 72
 14973                var identity = new ClaimsIdentity(claims, Scheme.Name);
 14974                var principal = new ClaimsPrincipal(identity);
 14975                var ticket = new AuthenticationTicket(principal, Scheme.Name);
 76
 14977                return AuthenticateResult.Success(ticket);
 78            }
 179            catch (AuthenticationException ex)
 80            {
 181                _logger.LogDebug(ex, "Error authenticating with {Handler}", nameof(CustomAuthenticationHandler));
 182                return AuthenticateResult.NoResult();
 83            }
 84            catch (SecurityException ex)
 85            {
 186                return AuthenticateResult.Fail(ex);
 87            }
 23388        }
 89    }
 90}