Какой статус-код HTTP следует возвращать, если срок действия токена (access token) истек?

«Какой статус-код HTTP следует возвращать, если срок действия токена (access token) истек?» — вопрос из категории Безопасность, который задают на 25% собеседований C# Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Согласно спецификации RFC 6750 (Bearer Token Usage) и общепринятой практике, для просроченного (или недействительного) токена должен возвращаться статус 401 Unauthorized.

Почему именно 401, а не 403?

  • 401 Unauthorized означает, что запрос не содержит корректных учетных данных для аутентификации. Сервер "не знает", кто вы. Просроченный токен — это некорректные учетные данные.
  • 403 Forbidden означает, что сервер понял, кто вы (аутентификация успешна), но у вас недостаточно прав для доступа к ресурсу. Это другая ситуация.

Правильная реализация в ASP.NET Core:

  1. В обработчике аутентификации (например, JWT Bearer): При проверке токена, если он просрочен, схема аутентификации автоматически завершится с ошибкой, и фреймворк вернет 401.

  2. Для явного возврата с дополнительной информацией (в контроллере или middleware):

    [Authorize]
    public class SecureController : ControllerBase
    {
        [HttpGet("data")]
        public IActionResult GetData()
        {
            // Проверка, выполненная кастомной логикой
            if (HttpContext.User.IsTokenExpired())
            {
                // Рекомендуется также добавить заголовок WWW-Authenticate
                Response.Headers.WWWAuthenticate = "Bearer error="invalid_token", error_description="The access token expired"";
                return Unauthorized(new { error = "invalid_token", message = "Token has expired" });
            }
            return Ok("Sensitive data");
        }
    }
  3. Использование [Authorize] с политиками: Можно создать политику, которая проверяет не только наличие, но и валидность/срок токена.

    services.AddAuthorization(options =>
    {
        options.AddPolicy("ValidToken", policy =>
            policy.RequireAssertion(context =>
                context.User.Identity?.IsAuthenticated == true && 
                !context.User.IsTokenExpired()));
    });

    Затем использовать [Authorize(Policy = "ValidToken")]. При неудаче политики также вернется 401.

Ключевой вывод: Всегда используйте 401 Unauthorized для проблем с аутентификацией (неверный/просроченный/отозванный токен). Используйте 403 Forbidden только когда пользователь аутентифицирован, но его роли или claims не позволяют выполнить действие.