public ValueTask <AuthenticationResult> AuthenticateAsync(string accessToken, CancellationToken cancellationToken)
    {
        var authInfo = _authenticationInformationProvider.GetProfileAuthenticationInformation();
        var result   = TryValidateToken(accessToken, authInfo);

        if (result != null)
        {
            return(new ValueTask <AuthenticationResult>(result));
        }

        foreach (var additionalAuthInfo in _authenticationInformationProvider.GetAdditionalProfileAuthenticationInformations())
        {
            result = TryValidateToken(accessToken, additionalAuthInfo);
            if (result != null)
            {
                return(new ValueTask <AuthenticationResult>(result));
            }
        }

        var serviceAuthInfo = _authenticationInformationProvider.GetServiceAuthenticationInformation();

        result = TryValidateToken(accessToken, serviceAuthInfo);
        if (result != null)
        {
            return(new ValueTask <AuthenticationResult>(result));
        }

        throw new NotSupportedException("Security token is not a valid JWT token.");
    }
    /// <summary>
    /// ASP.Net authentication & authorization, used by APIs and can be used
    /// by Services as well (for example, by SignalR hosts), but not by
    /// self-hosted services (e.g. with some custom TCP implementation).
    /// </summary>
    /// <returns></returns>
    public static IServiceCollection UseAspNetAuthentication(
        this IServiceCollection services,
        IAuthenticationInformationProvider authenticationInformationProvider)
    {
        services.AddTransient <RealtimeAuthenticationClient>();

        var profileAuthentication            = authenticationInformationProvider.GetProfileAuthenticationInformation();
        var serviceAuthentication            = authenticationInformationProvider.GetServiceAuthenticationInformation();
        var additionalProfileAuthentications = authenticationInformationProvider.GetAdditionalProfileAuthenticationInformations();

        if (profileAuthentication.TokenValidationParameters.ValidAudiences?.FirstOrDefault() == null ||
            (serviceAuthentication != null && serviceAuthentication.TokenValidationParameters.ValidAudiences?.FirstOrDefault() == null) ||
            additionalProfileAuthentications.Any(x => x.TokenValidationParameters.ValidAudiences?.FirstOrDefault() == null))
        {
            throw new InvalidOperationException("Call UseSomeProvider method on AuthenticationInformationBuilder before calling this method, so that ValidAudiences parameter is set up.");
        }

        var authenticationSchemes = new List <string>
        {
            profileAuthentication.SchemeName ?? throw new InvalidOperationException("Scheme name is empty.")
        };

        var authenticationBuilder = services
                                    .AddAuthentication(TyrAuthenticationSchemes.ProfileAuthenticationScheme) // Sets default authentication scheme.
                                    .AddJwtBearer(profileAuthentication.SchemeName, options => ConfigureOptions(options, profileAuthentication));

        foreach (var additionalAuthentication in additionalProfileAuthentications)
        {
            authenticationSchemes.Add(additionalAuthentication.SchemeName ?? throw new InvalidOperationException("Scheme name is empty."));
            authenticationBuilder.AddJwtBearer(additionalAuthentication.SchemeName, options => ConfigureOptions(options, additionalAuthentication));
        }

        if (serviceAuthentication != null)
        {
            authenticationSchemes.Add(serviceAuthentication.SchemeName ?? throw new InvalidOperationException("Scheme name is empty."));
            authenticationBuilder.AddJwtBearer(serviceAuthentication.SchemeName, options => ConfigureOptions(options, serviceAuthentication));
        }

        if (authenticationSchemes.Distinct().Count() != authenticationSchemes.Count)
        {
            throw new InvalidOperationException("Duplicate authentication schemes found.");
        }

        services.AddAuthorization(options =>
        {
            options.DefaultPolicy = new AuthorizationPolicyBuilder()
                                    .RequireAuthenticatedUser()
                                    .AddAuthenticationSchemes(authenticationSchemes.ToArray())
                                    .Build();
        });

        services.AddTransient <IHttpContextAccessor, HttpContextAccessor>();
        services.AddTransient <IProfileTokenService, HttpContextProfileTokenService>();

        return(services);
    }