Search code examples
c#asp.net-corejwtopeniddict

JWT Middleware not getting claims from OpenIddict Issued JWT


I am using OpenIddict to issue JWT tokens for my spa. I have the JWT being issued, but I am unable to get the claims out of them with the JWT Middleware. I have verified that the claims are being put into the token correctly. Note: I am using EF 6 and I am not using Identity

Startup.cs

public class Startup
{
    public Startup(IHostingEnvironment env)
    {
        var builder = new ConfigurationBuilder()
            .SetBasePath(env.ContentRootPath)
            .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
            .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: false)
            .AddEnvironmentVariables();
        Configuration = builder.Build();
    }

    public IConfigurationRoot Configuration { get; set; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddCors(options =>
        {
            options.AddPolicy(
                "CorsPolicy",
                builder =>
                builder.AllowAnyOrigin()
                .AllowAnyMethod()
                .AllowAnyHeader()
                .AllowCredentials());
        });

        services.AddTransient<IClaimsPrincipal, CustomClaimsPrincipal>(GetClaimsPrincipalProvider());
        services.AddTransient<ICustomClaimsPrincipal, CustomClaimsPrincipal>(GetClaimsPrincipalProvider());

        services.AddScoped(DbContext);

        services.AddMvc();

        services.AddIdentity<IClaimsPrincipal, ClaimsPrincipal>(config =>
        {
        }).AddDefaultTokenProviders();

    // configure open id
    services.AddOpenIddict()
            .AddCore(opt =>
            {
                opt.UseEntityFramework().UseDbContext<AuthorizationDbContext>();
            })
            .AddServer(opt =>
            {
                opt.UseMvc();

                opt.EnableTokenEndpoint("/api/ping");

                opt.AllowClientCredentialsFlow();

                opt.AllowPasswordFlow();

                opt.DisableHttpsRequirement();
                opt.UseJsonWebTokens();
                opt.AddSigningKey(signingKey);

                opt.AcceptAnonymousClients();
            });

        JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
        JwtSecurityTokenHandler.DefaultOutboundClaimTypeMap.Clear();

        services.AddAuthentication(options =>
        {
            options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
        })
            .AddJwtBearer(options =>
            {
                options.RequireHttpsMetadata = false;
                options.SaveToken = true;
                options.TokenValidationParameters = new TokenValidationParameters
                {
                };
            });
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, IServiceProvider serviceProvider)
    {
        app.UseCors("CorsPolicy");
        app.UseStaticFiles();

        app.UseAuthentication();
        app.UseSiteRouteMiddleware();

        app.UseHttpContextLogging();
        app.UseClaimsLogging();
        app.UseMiddleware<ExceptionMiddleware>();

        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "default",
                template: "{controller=Index}/{action=Index}");
        });
     }
}

Token Controller:

    [HttpPost]
    [AllowAnonymous]
    public async Task<IActionResult> Post()
    {
        var claims = new List<Claim>
        {
            new Claim(CustomClaimType.LoginName, customClaimsName.LoginName),
            new Claim(CustomClaimType.SiteKey, customClaimsName.SiteKey.ToString()),
            new Claim(CustomClaimType.Id, customClaimsName.PtKey.ToString()),
            new Claim(JwtRegisteredClaimNames.Iat, DateTime.UtcNow.ToString(), ClaimValueTypes.Integer64)
        };

        claims.Add(new Claim(OpenIdConnectConstants.Claims.Subject, "Portal"));

        foreach (var x in claims)
            x.SetDestinations(OpenIdConnectConstants.Destinations.AccessToken);

        var identity = new ClaimsIdentity(claims, "OpenIddict");
        var principal = new ClaimsPrincipal(identity);

        // Create a new authentication ticket holding the user identity.
        var ticket = new AuthenticationTicket(
            principal,
            new AuthenticationProperties(),
            OpenIdConnectServerDefaults.AuthenticationScheme);

        // Returning a SignInResult will ask OpenIddict to issue the appropriate access/identity tokens.
        return SignIn(ticket.Principal, ticket.Properties, ticket.AuthenticationScheme);
    }
}

When I add try to get the claims from User.Claims, there is nothing inside the token. What am I missing in the middleware or OpenIddict configuration?

Test Controller

[HttpGet("test")]
[AllowAnonymous]
public IActionResult Get()
{
    var temp = User.Claims;
    return Ok(temp);
}

Solution

  • Your ASP.NET Core JWT bearer handler configuration is invalid: it neither uses automatic discovery (because the options.Authority property is not set) nor includes the token validation parameters (like the issuer, the audience and the signing key).

    Since the configuration is not valid, the token validation logic can't be applied and User.Claims is always empty.

    Set options.Authority and options.Audience and it should work. Alternatively, switch back to the OpenIddict validation handler and the default token format, that offers a simpler configuration experience.