Adrian Abadín
Adrian Abadín

Reputation: 15

.NET 8 Facebook Authentication in Web API Challenge Exception - Redirect After Challenge?

Context: Im Developing a WEB API in .NET 8 with Facebook Authentication using .net 8 identity core

Desired Behavior: I need the api to expose a Get endpoint and start Facebook Authentication flow when the endpoint is hit.

Problem

Conclusion I dont know if this is the flow expected for a .NET API, but it seemed to have issues setting my response. Thanks For your time, ive been looking for this on the web and i dont seemed to find an answer.

Program.cs

using emps.DTO;
using emps.Models;
using emps.Repository;
using emps.Services;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.Facebook;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.Filters;

var builder = WebApplication.CreateBuilder(args);

// CORS CONFIGURATION
builder.Configuration.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
builder.Services.AddCors(options => {
    options.AddPolicy("debug", cors => {
        cors.AllowAnyMethod();
        cors.AllowCredentials();
        cors.AllowAnyHeader();
        cors.WithOrigins("https://localhost:3000");

    });
});
builder.Services.Configure<AppSettings>(builder.Configuration.GetSection(""));
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();

//IDENTITY CONFIGURATION
builder.Services.Configure<IdentityOptions>(options =>
{
    options.User.RequireUniqueEmail = true;
    options.Password.RequireNonAlphanumeric = false;
    options.Lockout.AllowedForNewUsers = true;
    options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5);
    options.Lockout.MaxFailedAccessAttempts = 5;
});

builder.Services.AddAuthentication(options =>{
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = FacebookDefaults.AuthenticationScheme;
}).AddFacebook(options => {
    options.AppId = builder.Configuration["appId"] ?? "";
    options.AppSecret = builder.Configuration["appSecret"] ?? "";
    options.CallbackPath = "/api/Auth/cb";
    options.Scope.Add("pages_manage_engagement");
    options.Scope.Add("pages_manage_posts");
    options.Scope.Add("pages_read_engagement");
    options.Scope.Add("publish_video");
    options.Scope.Add("public_profile");
    options.Scope.Add("email");
    options.Fields.Add("email");
    options.Fields.Add("name");
});
//COOKIE CONFIGURATION
builder.Services.ConfigureApplicationCookie(options => {
    options.Cookie.Name = "mytoken";
    options.Cookie.HttpOnly = true;
    options.ExpireTimeSpan = TimeSpan.FromMinutes(30);
    options.SlidingExpiration = true;
    options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
    options.Cookie.SameSite = SameSiteMode.Lax;
});

builder.Services.AddIdentityApiEndpoints<User>().AddEntityFrameworkStores<IdentityContext>();
//SWAGGER Configuration

builder.Services.AddSwaggerGen(options =>
{
    options.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
    {
        In = ParameterLocation.Header,
        Name = "Authorization",
        Type = SecuritySchemeType.ApiKey

    });
    options.OperationFilter<SecurityRequirementsOperationFilter>();


});
// DB Context
builder.Services.AddDbContext<IdentityContext>(options => {
    options.UseSqlServer(builder.Configuration.GetConnectionString("defaultConnection"));
});



//Repositorios

builder.Services.AddScoped<PostRepository>();
builder.Services.AddScoped<UsersRepository>();
//Servicios
builder.Services.AddScoped<PostService>();
builder.Services.AddScoped<UsersService>();
//builder.Services.AddHttpClient();
builder.Services.AddScoped<FacebookService>();
builder.Services.AddAuthorization();
var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.MapIdentityApi<User>();

app.UseCors((options) => {
    options.AllowAnyHeader();
    options.AllowCredentials();
    options.AllowAnyMethod();
    options.AllowAnyHeader();
    options.SetIsOriginAllowedToAllowWildcardSubdomains();
    options.WithOrigins(["https://localhost:3000", "https://web.facebook.com"]);
});
app.UseAuthentication();
app.UseAuthorization();


app.MapControllers();

app.Run();

Controller Routes

        public async Task< IActionResult> FacebookLogin() {
            var properties = this.SignInManager.ConfigureExternalAuthenticationProperties("Facebook", null);
            properties.RedirectUri = Url.Action("FacebookCb", "Auth");
            return Challenge(properties,"Facebook");
                          
        }
        [HttpGet("cb")]
        public async Task<IActionResult> FacebookCb(string code)
        {
            
                Console.WriteLine(code);
                var response = await this.SignInManager.GetExternalLoginInfoAsync();
                if (response != null)
                {
                    var email = response.Principal.FindFirst(x => x.Type == ClaimTypes.Email);
                    var username = response.Principal.FindFirst(x => x.Type == ClaimTypes.Name);
                    if (email != null && username != null)
                    {
                        User userData = new User { Email = email.Value, UserName = username.Value };
                        await SignInManager.SignInAsync(userData, true);
                        var myUser = await this._service.GetUser(email.Value);
                        if (myUser != null)
                        {
                            if (response != null && response.AuthenticationTokens != null)
                            {
                                var token = response.AuthenticationTokens.FirstOrDefault(e => e.Name == "access_token");
                            }
                        }

                    }
                }
                return NoContent();
            
        }

System.InvalidOperationException: StatusCode cannot be set because the response has already started.
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ThrowResponseAlreadyStartedException(String value)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.set_StatusCode(Int32 value)
   at Microsoft.AspNetCore.Http.DefaultHttpResponse.Redirect(String location, Boolean permanent)
   at Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler`1.HandleRequestAsync()
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
   at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)
   at Microsoft.WebTools.BrowserLink.Net.BrowserLinkMiddleware.InvokeAsync(HttpContext context)
   at Microsoft.AspNetCore.Watch.BrowserRefresh.BrowserRefreshMiddleware.InvokeAsync(HttpContext context)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequests[TContext](IHttpApplication`1 application)

Thanks For your time I hope my question is clear enoght

Upvotes: 0

Views: 63

Answers (0)

Related Questions