You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修改WebApi过期Refresh Token的响应状态码与返回体?

How to Customize Response Status Code and Body When Refresh Token Expires in WebAPI?

I'm working with a WebAPI where expired Refresh Tokens default to returning a 400 status code with the response body {"Error":"invalid_client"}. I want to modify both the status code and response body content for this scenario.

So far, I've added a header flag in my code like this:

public async Task ReceiveAsync(AuthenticationTokenReceiveContext context) 
{ 
    AuthenticationTicket ticket; 
    if (_refreshTokens.TryRemove(context.Token, out ticket)) 
    { 
        if (ticket.Properties.ExpiresUtc.HasValue && ticket.Properties.ExpiresUtc.Value.LocalDateTime < DateTime.Now) 
        { 
            context.Response.Headers.Add("Expired", new string[] { "Yes" }); 
        } 
        context.SetTicket(ticket); 
    } 
}

Could anyone help me figure out how to fully customize the response? Thanks!


Answer

Absolutely, you can fully customize the response—your current approach of adding a header is a good start, but we need to override the default response handling entirely. Here are two straightforward methods to achieve this:

Method 1: Build a Custom Response Directly in ReceiveAsync

When you detect an expired refresh token, you can skip the default middleware logic and write your own status code and response body directly. The key is to call context.HandleResponse() to signal that you've taken care of the response.

public async Task ReceiveAsync(AuthenticationTokenReceiveContext context)
{
    if (_refreshTokens.TryRemove(context.Token, out var ticket))
    {
        // Check if the token is expired
        if (ticket.Properties.ExpiresUtc.HasValue && ticket.Properties.ExpiresUtc.Value.LocalDateTime < DateTime.Now)
        {
            // Set a more semantically accurate status code (401 instead of 400)
            context.Response.StatusCode = StatusCodes.Status401Unauthorized;
            // Define the content type for your response
            context.Response.ContentType = "application/json";
            // Create your custom response body
            var customResponse = new 
            {
                Error = "refresh_token_expired",
                Message = "Your refresh token has expired. Please log in again to get a new token.",
                ExpiredAt = ticket.Properties.ExpiresUtc.Value.UtcDateTime
            };
            // Serialize and write the response
            await context.Response.WriteAsync(JsonSerializer.Serialize(customResponse));
            // Tell the middleware we've handled the response—prevents default 400 output
            context.HandleResponse();
            return;
        }
        context.SetTicket(ticket);
    }
    else
    {
        // Optional: Customize response for invalid/non-existent tokens too
        context.Response.StatusCode = StatusCodes.Status400BadRequest;
        context.Response.ContentType = "application/json";
        await context.Response.WriteAsync(JsonSerializer.Serialize(new 
        {
            Error = "invalid_refresh_token",
            Message = "The provided refresh token is not valid."
        }));
        context.HandleResponse();
    }
}

Key Notes for This Method:

  • context.HandleResponse() is critical—it stops the default middleware from generating the invalid_client response.
  • Using 401 Unauthorized is more semantically correct for expired credentials than the default 400, but you can adjust the status code to fit your API's conventions.
  • If you're using Newtonsoft.Json instead of System.Text.Json, replace JsonSerializer.Serialize with JsonConvert.SerializeObject.

Method 2: Use a Custom OAuth2 Error Handler (For Identity/OAuth2 Setups)

If your project uses ASP.NET Core Identity or OAuth2 middleware, you can hook into authentication events to centralize error handling:

services.AddAuthentication(options =>
{
    // Your base authentication configuration here
})
.AddJwtBearer(options =>
{
    options.Events = new JwtBearerEvents
    {
        OnAuthenticationFailed = context =>
        {
            if (context.Exception is SecurityTokenExpiredException)
            {
                context.Response.StatusCode = StatusCodes.Status401Unauthorized;
                context.Response.ContentType = "application/json";
                context.Response.WriteAsync(JsonSerializer.Serialize(new 
                {
                    Error = "token_expired",
                    Message = "Your authentication token has expired."
                }));
            }
            return Task.CompletedTask;
        }
    };
});

This works best for access token expiration, but for refresh token-specific handling, Method 1 is more direct since it operates directly in the token receive pipeline.


内容的提问来源于stack exchange,提问作者Jeremy Loh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 09:41:54