OAuth2 callback redirects user to authorization page

iKingNinja 120 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.

Developer technologies | ASP.NET | ASP.NET Core
Developer technologies | C#
{count} votes

1 answer

Sort by: Most helpful
  1. iKingNinja 120 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

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.