OAuth2 callback redirects user to authorization page

iKingNinja 60 Reputation points
2024-04-22T21:21:27.0266667+00:00

I am implementing OAuth2 authorization in my application with an external provider. When the user is redirected back to my application from the authorization server, my application will just redirect the user back despite using the Redirect() method to specify the URL.

Program.cs

builder.Services
    .AddAuthentication(options =>
    {
        options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        options.DefaultChallengeScheme = "ExternalProvider";
    })
    .AddCookie()
    .AddOAuth("ExternalProvider", options =>
    {
        ...
        options.CallbackPath = new PathString("/auth/callback");
        ...
        options.Events.OnCreatingTicket = async context =>
        {
            HttpRequestMessage req = new(HttpMethod.Get, context.Options.UserInformationEndpoint);
            req.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
            req.Headers.Authorization = new AuthenticationHeaderValue("Bearer", context.AccessToken);
            HttpResponseMessage res = await context.Backchannel.SendAsync(req, HttpCompletionOption.ResponseHeadersRead, context.HttpContext.RequestAborted);
            res.EnsureSuccessStatusCode();
            var user = JsonDocument.Parse(await res.Content.ReadAsStringAsync()).RootElement;
            context.RunClaimActions(user);
            // Save user to database if it doesn't exist
            ApplicationDbContext dbContext = context.HttpContext.RequestServices.GetRequiredService<ApplicationDbContext>();
            int userId = int.Parse(user.GetString("sub"));
            // Check if user exists
            bool userExists = (await dbContext.Users.FirstOrDefaultAsync(u => u.Id == userId)) is not null;
            if (!userExists)
            {
                // Save the user
                string username = user.GetString("preferred_username");
                string profilePicture = user.GetString("picture");
                dbContext.Users.Add(new ApplicationUser()
                {
                    Id = userId,
                    Username = username,
                    ProfilePicture = profilePicture
                });
                await dbContext.SaveChangesAsync();
            }
            context.Response.Redirect("/Home/Index"); // User is still redirected to /auth/login
        };
    });

AuthController.cs

using Microsoft.AspNetCore.Mvc;
namespace Frontend.Controllers
{
    public class AuthController : Controller
    {
        public IActionResult Login()
        {
            return Challenge("ExternalProvider");
        }
    }
}

HomeController.cs

using Microsoft.AspNetCore.Mvc;
namespace Frontend.Controllers
{
    public class HomeController : Controller
    {
        public IActionResult Index()
        {
            return View();
        }
    }
}

I want to return a MVC view after the authorization process is completed and I'm attempting to do it by redirecting the user to the home controller but with no success since the user will just be redirected back to the authorization.

ASP.NET Core
ASP.NET Core
A set of technologies in the .NET Framework for building web applications and XML web services.
4,239 questions
C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
10,385 questions
{count} votes

1 answer

Sort by: Most helpful
  1. iKingNinja 60 Reputation points
    2024-04-22T22:07:19.05+00:00

    It turned out that the callback was redirecting the user to the authorization page because the request wasn't being completed. I fixed the issue by calling context.Response.CompleteAsync().

    Let me know if this is the proper way of doing this.

    0 comments No comments