question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Should return 401 but is returning 404

See original GitHub issue

Hi!

I’m trying to test my web api when user has an invalid access token, but instead of 401, I’m getting an 404 result.

Here is my startup

public class Startup
    {
        private readonly IHostingEnvironment _environment;

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

            _environment = env;
        }

        public IConfigurationRoot Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddSingleton(Configuration);

            services.AddCors();
            // Add framework services.
            services.AddMvc();

            services.AddAuthorization();

            // Register the OpenIddict services.
            // Note: use the generic overload if you need
            // to replace the default OpenIddict entities.
            services.AddOpenIddict()
                // Register the Entity Framework stores.
                .AddEntityFrameworkCoreStores<ApplicationDbContext>()

                // Register the ASP.NET Core MVC binder used by OpenIddict.
                // Note: if you don't call this method, you won't be able to
                // bind OpenIdConnectRequest or OpenIdConnectResponse parameters.
                .AddMvcBinders()

                // .UseJsonWebTokens()

                // Enable the token endpoint (required to use the password flow).
                .EnableTokenEndpoint("/connect/token")
                .EnableRevocationEndpoint("/connect/logout")

                // Allow client applications to use the grant_type=password flow.
                .AllowPasswordFlow()
                .AllowRefreshTokenFlow()

                // During development, you can disable the HTTPS requirement.
                .DisableHttpsRequirement()

                .SetAccessTokenLifetime(TimeSpan.FromHours(5))
                .SetRefreshTokenLifetime(TimeSpan.FromHours(10))

                // Register a new ephemeral key, that is discarded when the application
                // shuts down. Tokens signed using this key are automatically invalidated.
                // This method should only be used during development.
                .AddEphemeralSigningKey();

            services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();

            var iocContainer = new ApplicationIoCContainer(services, Configuration);
            iocContainer.RegisterModules();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
        {
            loggerFactory.AddConsole(Configuration.GetSection("Logging"));
            loggerFactory.AddDebug();

            app.UseCors(builder =>
            // This will allow any request from any server. Tweak to fit your needs!
            // The fluent API is pretty pleasant to work with.
            builder.AllowAnyHeader()
                    .AllowAnyMethod()
                    .AllowAnyOrigin()
            );

            app.UseIdentity();

            app.UseOAuthValidation();

            app.UseOpenIddict();

            app.UseMvc();

            // Chamar apenas quando for criar as tabelas do banco
            InitializeAsync(app.ApplicationServices, CancellationToken.None).GetAwaiter().GetResult();
        }

        private async Task InitializeAsync(IServiceProvider services, CancellationToken cancellationToken)
        {
            // Create a new service scope to ensure the database context is correctly disposed when this methods returns.
            using (var scope = services.GetRequiredService<IServiceScopeFactory>().CreateScope())
            {
                var context = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
                // ReSharper disable once MethodSupportsCancellation
                await context.Database.EnsureCreatedAsync();

                var manager = scope.ServiceProvider.GetRequiredService<OpenIddictApplicationManager<OpenIddictApplication>>();

                if (await manager.FindByClientIdAsync("ClientId", cancellationToken) == null)
                {
                    var application = new OpenIddictApplication
                    {
                        ClientId = "ClientId",
                        DisplayName = "Client name",

                        // I guess my error is here... but don't know how to resolve with an Api
                        LogoutRedirectUri = "http://localhost:5000/signout-oidc",
                        RedirectUri = "http://localhost:5000/signin-oidc"
                    };

                    await manager.CreateAsync(application, cancellationToken);
                }
            }
        }
    }

and this is the generated log

info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
      Request starting HTTP/1.1 GET http://localhost:5000/api/program/get-paged?page=1&pagesize=100
info: AspNet.Security.OAuth.Validation.OAuthValidationMiddleware[7]
      Bearer was not authenticated. Failure message: Authentication failed because the access token was invalid.
info: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2]
      Authorization failed for user: (null).
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1]
      Authorization failed for the request at filter 'Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter'.
info: Microsoft.AspNetCore.Mvc.ChallengeResult[1]
      Executing ChallengeResult with authentication schemes ().
info: AspNet.Security.OAuth.Validation.OAuthValidationMiddleware[12]
      AuthenticationScheme: Bearer was challenged.
info: Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationMiddleware[12]
      AuthenticationScheme: Identity.Application was challenged.
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]
      Executed action Life.Platform.Api.Controllers.ProgramController.Get (Life.Platform.Api) in 55.8041ms
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
      Request finished in 60.6096ms 302
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
      Request starting HTTP/1.1 GET http://localhost:5000/Account/Login?ReturnUrl=%2Fapi%2Fprogram%2Fget-paged%3Fpage%3D1%26pagesize%3D100
info: AspNet.Security.OAuth.Validation.OAuthValidationMiddleware[7]
      Bearer was not authenticated. Failure message: Authentication failed because the access token was invalid.
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
      Request finished in 5.0739ms 404

Looks like it’s using CookieMiddlware, but why? And, how can I just return a 401 result, when the user is unautenticated and 403 when user is unauthorized?

Thanks for your help! And congrats… This is a big tool!!!

Issue Analytics

  • State:closed
  • Created 7 years ago
  • Comments:6 (1 by maintainers)

github_iconTop GitHub Comments

6reactions
MaciejWanatcommented, Dec 12, 2017

@weitzhandler, I’ve used following workaround:

        services.ConfigureApplicationCookie(options =>
        {
            options.Events.OnRedirectToLogin = context =>
            {
                context.Response.StatusCode = 401;
                return Task.CompletedTask;
            };
        });

If you call this in ConfigureServices method, it sets up the cookie to return 401 on redirection to login. I think this won’t be a good solution if you use this redirection somewhere else in a code. Otherwise - should work.

4reactions
kevinchaletcommented, Jan 20, 2017

And congrats… This is a big tool!!!

Glad you like it 😄

The behavior you’re seeing is caused by Identity, that replaces 401 responses by 302 responses. In your case, the login endpoint doesn’t exist, so you’re getting a 404 response.

If you’re not using cookies authentication, consider removing app.UseIdentity();.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Is it OK to return a HTTP 401 for a non existent resource ...
If the user does not have access to a resource, you should be returning 403, not 404. If the user is authenticated and...
Read more >
Hands off that resource, HTTP status code 401 vs 403 vs 404
Returning a 404 Not Found means “the requested resource does not exists”. Actually, there's a subtlety, it could mean “the requested resource ...
Read more >
The 404 response could also indicate a permissions ...
The reason why this happens instead of returning a 401 is that it would leak information to which the user is not privileged....
Read more >
Is it OK to give status 404 to unauthorized users?
Certainly a valid argument for a 404. However, I don't think it's necessarily always appropriate to send a 404 - it depends on...
Read more >
Handling Forbidden RESTful Requests: 401 vs. 403 vs. 404
If the request method was not HEAD and the server wishes to make public why the request has not been fulfilled, it SHOULD...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found