Custom 401 response .NET Core 5 API
Hej!
Testar att bygga ett api i .NET Core 5 men har problem med autentiseringsdelen.
För tillfället använder jag [Authorize]-attributen för controllern, vilket fungerar.
Men jag skulle vilja att det returneras tillbaka ett response i stil med:
{
"status": 401,
"message": "Unauthorized"
}
Alternativt göra såhär, dock mycket som repeteras och känns inte som best practise?
https://i.imgur.com/y8u9DcN.jpg
Det verkar även gå att göra egen middelware men fick inte fram något som hjälpte mig. Någon som kanske kan förklara?
Jag har även försökt med att göra egna attributer men det känns som att dessa inte riktigt passar för APIer(?).
Använder du JWT? Då kan du konfigurera det i din service container.
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(o =>
{
o.TokenValidationParameters = new TokenValidationParameters
{
ValidIssuer = ...
...
};
o.Events = new JwtBearerEvents
{
OnChallenge = async context =>
{
// Applicera vilken statuskod som ska sättas
context.Response.StatusCode = StatusCodes.Status401Unauthorized;
await context.Response.WriteAsJsonAsync(new
{
Status = context.Response.StatusCode,
Message = "Unauthorized"
});
context.HandleResponse();
}
};
});

Dock så brukar det räcka med att få tillbaka en 401 så får frontend hantera hur detta ska visas eller om man ska omdirigeras. Felmeddelandet visas i en header som heter WWW-Authenticate.
Gör du som ovan så kommer denna header att försvinna:

Vill du ha med denna också så får du lägga till den manuellt.
context.Response.Headers.Append(HeaderNames.WWWAuthenticate, $"{context.Options.Challenge} error={context.Error}, error_description={context.ErrorDescription}");
Använder du JWT? Då kan du konfigurera det i din service container.
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(o =>
{
o.TokenValidationParameters = new TokenValidationParameters
{
ValidIssuer = ...
...
};
o.Events = new JwtBearerEvents
{
OnChallenge = async context =>
{
// Applicera vilken statuskod som ska sättas
context.Response.StatusCode = StatusCodes.Status401Unauthorized;
await context.Response.WriteAsJsonAsync(new
{
Status = context.Response.StatusCode,
Message = "Unauthorized"
});
context.HandleResponse();
}
};
});
https://i.imgur.com/WIptDuu.png
Dock så brukar det räcka med att få tillbaka en 401 så får frontend hantera hur detta ska visas eller om man ska omdirigeras. Felmeddelandet visas i en header som heter WWW-Authenticate.
Gör du som ovan så kommer denna header att försvinna:
https://i.imgur.com/icuIVdN.png
Vill du ha med denna också så får du lägga till den innan context.HandleResponse();
context.Response.Headers.Append(HeaderNames.WWWAuthenticate, $"{context.Options.Challenge} error={context.Error}, error_description={context.ErrorDescription}");
Detta var precis vad jag letade efter, stort tack!
När jag gör ett request postman får jag dock inte statuskoden i WWW-Authenticate headern, både med och utan koden som du skickade. Den har value = Bearer. Se bild.
EDIT: Glömde context.HandleResponse(); Mycket riktigt så försvann nu WWW-Authenticate headern. Dock fungerade det utan HandleResponse(), vad är det den gör?
En följdfråga, om jag vill lägga till ett eget 403 meddelande, lägger jag till ett nytt "o.Events...."-block eller är det ett "OnChallenge...."-block som behövs?

Detta var precis vad jag letade efter, stort tack!
När jag gör ett request postman får jag dock inte statuskoden i WWW-Authenticate headern, både med och utan koden som du skickade. Den har value = Bearer. Se bild.
EDIT: Glömde context.HandleResponse(); Mycket riktigt så försvann nu WWW-Authenticate headern. Dock fungerade det utan denna, vad är det den gör?
En följdfråga, om jag vill lägga till ett eget 403 meddelande, lägger jag till ett nytt "o.Events...."-block eller är det ett "OnChallenge...."-block som behövs?
WWW-Authenticate är en standardiserad header som sätts vid 401 som anger hur man bör agera för att få tillgång till det efterfrågade. I exemplet ovan så är det Bearer token (JWT) som ska användas och orsaken till 401 är att token som använts gått ut.
HandleResponse() skippar all default logik för din Challenge. Dvs det som annars sätts automatiskt.
403 är Forbidden, det är då man är autentiserad men saknar behörighet.
Har korrigerat hur jag skriver ut objektet jämfört med första exemplet. Tror det är bättre att använda WriteAsync med JsonSerializer då default behavior för WriteJsonAsync sätter response till 200OK (vilket skulle kunna skapa problem).
La även på Content-Type header i svaret då du returerar JSON nu istället för enbart en header.
o.Events = new JwtBearerEvents
{
OnChallenge = async context =>
{
context.Response.ContentType = "application/json";
context.Response.StatusCode = StatusCodes.Status401Unauthorized;
await context.Response.WriteAsync(JsonSerializer.Serialize(new
{
Status = context.Response.StatusCode,
Message = "Unauthorized"
}));
context.HandleResponse();
},
OnForbidden = async context =>
{
context.Response.ContentType = "application/json";
context.Response.StatusCode = StatusCodes.Status403Forbidden;
await context.Response.WriteAsync(JsonSerializer.Serialize(new
{
Status = context.Response.StatusCode,
Message = "Forbidden"
}));
},
};
WWW-Authenticate är en standardiserad header som sätts vid 401 som anger hur man bör agera för att få tillgång till det efterfrågade. I exemplet ovan så är det Bearer token (JWT) som ska användas och orsaken till 401 är att token som använts gått ut.
HandleResponse() skippar all default logik för din Challenge. Dvs det som annars sätts automatiskt.
403 är Forbidden, det är då man är autentiserad men saknar behörighet.
Har korrigerat hur jag skriver ut objektet jämfört med första exemplet. Tror det är bättre att använda WriteAsync med JsonSerializer då default behavior för WriteJsonAsync sätter response till 200OK (vilket skulle kunna skapa problem).
La även på Content-Type header i svaret då du returerar JSON nu istället för enbart en header.
o.Events = new JwtBearerEvents
{
OnChallenge = async context =>
{
context.Response.ContentType = "application/json";
context.Response.StatusCode = StatusCodes.Status401Unauthorized;
await context.Response.WriteAsync(JsonSerializer.Serialize(new
{
Status = context.Response.StatusCode,
Message = "Unauthorized"
}));
context.HandleResponse();
},
OnForbidden = async context =>
{
context.Response.ContentType = "application/json";
context.Response.StatusCode = StatusCodes.Status403Forbidden;
await context.Response.WriteAsync(JsonSerializer.Serialize(new
{
Status = context.Response.StatusCode,
Message = "Forbidden"
}));
},
};
Får inte headern att fungera. Har testat både den som du skrev samt den som jag kommenterat ut men lyckas inte få med den oavsett.
EDIT: Löste sig genom att flytta tilläggningen av headern innan WriteAsync()

Får inte headern att fungera. Har testat både den som du skrev samt den som jag kommenterat ut men lyckas inte få med den oavsett.
EDIT: Löste sig genom att flytta tilläggningen av headern innan WriteAsync()
https://i.imgur.com/Z2DmuQK.png
Ja, WriteAsync är som din return. Så du måste sätta statuskod, headers etc innan du skriver.
Ja, WriteAsync är som din return. Så du måste sätta statuskod, headers etc innan du skriver.
Grymt! Då tror jag nog att jag kommer vidare.
Stort tack för hjälpen!
- Missljud från ny fläkt, webhallen vill reparera inställer för att byta ut69
- C++ och dess framtid att programmera minnessäkert - Hur går utvecklingen?1,5k
- Reklamationsrätt Google Pixel 6a Batteriproblem (Elgiganten) Struntar i Konsumentköpslagen (Löst)18
- Ny CPU15
- IPS gaming skärmar, vilka problem har de i 2025?5
- Vad är min begagnade skärm/TV värd?495
- Sweklockers nere16
- Köpråd NAS / raid - önskar även extern access1
- [LEK] Gissa spelet19k
- Jobben som påverkas mest och minst av AI79
- Säljes Lenovo Yoga Pro 7 14ASP9 (OLED 120Hz, AI 365, 32GB, 1TB)
- Säljes IDOBAO ID80V2 Gateron INK Black V2 (ISO)
- Säljes Två LGA2011 (v1) moderkort från workstation-datorer (Asus / HP)
- Köpes Ryzen 7 - 5800X3D
- Säljes GMMK TKL och GMMK Compact keycaps och Switchar
- Säljes Table Top arcade maskin 1-2 player
- Säljes Legion Pro 7 16IRX9H | 14900HX | 4080 | 32GB ram
- Säljes Vattenblock - EK-Quantum Velocity² D-RGB - 1700 Nickel + Plexi
- Säljes i5 13600KF och en ASUS Prime Z690 medföljande NZXT Kraken 280MM
- Säljes Fractal Epoch, Vertex 750, RX6800
- Kommentar: Det är aldrig rätt tid att köpa21
- Udda mATX-moderkort har fastlödd Ryzen-processor21
- AMD lägger ned styrkretsen B65027
- Noctua: Vi vill göra RTX 509023
- AMD läckte FSR 4-kod - stöd för äldre kort kan vara på väg14
- Populär Chrome-VPN avslöjad - spionerar på användare90
- 5K2K-upplösning vid 180 Hz i ny Samsung-skärm38
- Microsoft bekräftar SSD-problem30
- Gigabyte lanserar externt RTX 5090 med vätskekylning14
- Quiz: Vad är det för hårdvarumojäng på bilden?110
Externa nyheter
Spelnyheter från FZ