// SPDX-FileCopyrightText: 2026 Progmasoft // SPDX-License-Identifier: AGPL-3.0-or-later WITH AdditionRef-Progmasoft-Patent-Grant-1.1 using Microsoft.AspNetCore.Authentication; namespace Progmasoft.Progmaweb.Api.Accounts; /// Ends a Google callback that cannot finish: it records why and returns to the sign-in page. /// /// The visitor sees one message for every cause, so the log is where the cause can be read. The entry names the /// error Google reported, such as access_denied, or the reason the handler refused the callback, such as a /// missing or invalid state. It never contains the authorization code, the state or a token. /// internal static class GoogleSignInFailure { /// The page that explains a failed Google sign-in. public const string SignInPage = "/login?google=failed"; /// Writes the cause of a failed Google callback. private static readonly Action FailureReport = LoggerMessage.Define( LogLevel.Warning, new EventId(5, "GoogleSignInFailed"), "Google sign-in could not be completed: {Reason}"); /// The longest provider error code that is written as it was sent. private const int MaximumErrorLength = 64; /// Records the cause of the failure and redirects to . /// The failed remote authentication. /// Receives the cause. /// A completed task; the response is handled. public static Task HandleAsync(RemoteFailureContext context, ILogger logger) { FailureReport(logger, Reason(context), null); context.Response.Redirect(SignInPage); context.HandleResponse(); return Task.CompletedTask; } /// Describes why the callback failed, in words safe to log. /// The failed remote authentication. /// The error Google reported, or the reason the handler refused the callback. internal static string Reason(RemoteFailureContext context) { string? error = context.Request.Query["error"]; if (!string.IsNullOrEmpty(error)) { // The value comes from the query string, so only a short code of safe characters is written as it is. bool plain = error.Length <= MaximumErrorLength && error.All(character => char.IsAsciiLetterOrDigit(character) || character is '_' or '-' or '.'); return plain ? $"Google reported {error}" : "Google reported an unrecognized error"; } string? message = context.Failure?.InnerException?.Message ?? context.Failure?.Message; return string.IsNullOrWhiteSpace(message) ? "the callback could not be processed" : message; } }