Integrating Auth0 to ASP.NET Core 3.1 MVC application

56 Views Asked by At

We need to integrate an ASP.NET 3.1 Core MVC application with Auth0. Auth0 does not have any sample application which demonstrated how to integrate.

We downloaded Auth0 sample for ASP.NET Core 2.1 and updated the framework to .NET Core 3.1 and resolved the errors.

When we run the application, we are still getting the following error:

"error": {
    "message": "Federated clients cannot access non-authority tenants.",
    "oauthError": "invalid_request",
    "type": "request-error"
}

This is the code in startup.cs:

using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OAuth;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.VisualStudio.Web.CodeGeneration;
using Newtonsoft.Json;
using SampleMvcApp.Support;
using System;
using System.Collections.Generic;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;

namespace SampleMvcApp
{
    public class Startup
    {
        public Startup(IConfiguration configuration, Microsoft.AspNetCore.Hosting.IWebHostEnvironment hostingEnvironment)
        {
            Configuration = configuration;
            HostingEnvironment = hostingEnvironment;
        }

        public IConfiguration Configuration { get; }
        // public IHostingEnvironment HostingEnvironment { get; }
        public Microsoft.AspNetCore.Hosting.IWebHostEnvironment HostingEnvironment { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.ConfigureSameSiteNoneCookies();
            services.AddMvc(options => options.EnableEndpointRouting = false);

            // Add authentication services
            services.AddAuthentication(options =>
            {
                options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            })
            .AddCookie()
            .AddOAuth("Auth0", options =>
            {
                options.ClientId = $"https://{Configuration["Auth0:Domain"]}";
                options.ClientSecret = Configuration["Auth0:ClientSecret"];
                // options.ResponseType = "code";
                options.Scope.Clear();
                options.Scope.Add("openid");

                options.CallbackPath = new PathString("/callback");

                options.SaveTokens = true;

                options.AuthorizationEndpoint = "https://dev-p0bgfnzdg04hpebl.us.auth0.com/authorize";
                options.TokenEndpoint = "https://dev-p0bgfnzdg04hpebl.us.auth0.com/oauth/token";

                options.Events = new OAuthEvents
                {
                    OnCreatingTicket = context =>
                    {
                        var accessToken = context.AccessToken;
                        var base64Payload = accessToken.Split('.')[1];
                        var bytes = Convert.FromBase64String(base64Payload);
                        var jsonPayload = Encoding.UTF8.GetString(bytes);
                        var claims = JsonConvert.DeserializeObject<Dictionary<string, string>>(jsonPayload);

                        foreach (var (type, value) in claims)
                        {
                            context.Identity.AddClaim(new Claim(type, value));
                        }
                        return Task.CompletedTask;
                    }
                };
            });

            services.AddMvc()
                .SetCompatibilityVersion(CompatibilityVersion.Version_3_0);
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, Microsoft.AspNetCore.Hosting.IWebHostEnvironment env)
        {
            // env.EnvironmentName
            if (env.EnvironmentName == "Development")
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
                app.UseHsts();
            }

            app.UseStaticFiles();
            app.UseCookiePolicy();

            app.UseAuthentication();

            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");
            });
        }
    }
}

Any inputs would be helpful.

We know that .NET Core 3.1 is no longer supported by Microsoft. But we need to crack this. Someone might have done this before.

Thanks in advance, Siddarth

1

There are 1 best solutions below

0
spalMcc On

As per Auth0 team, there is no SDK for ASP.NET Core 3.1 MVC based applications. But this is not 100% correct.

We managed to find the solutin and following are the steps:-

1: Get sample code from Auth0 for ".NET6". 2: Update the package "Auth0.AspNetCore.Authentication" to version "1.0.4" which is compatible to ASP.NET Core 3.1 Framework 3: Update the package "Microsoft.AspNetCore.Authentication.JwtBearer" to "3.1.32" which is compatible to ASP.NET Core 3.1 Framework 4: Change the "program.cs" as follows and add "Startup.cs" as follows too.


For Front end

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using Microsoft.AspNetCore;

namespace SampleMvcApp
{
    public class Program
    {
        public static void Main(string[] args)
        {
            CreateWebHostBuilder(args).Build().Run();
        }

        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .UseStartup<Startup>();
    }
}

    using Microsoft.AspNetCore.Authentication.Cookies;
    using Microsoft.AspNetCore.Authentication.OpenIdConnect;
    using Microsoft.AspNetCore.Builder;
    using Microsoft.AspNetCore.Hosting;
    using Microsoft.AspNetCore.Http;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.Hosting.Internal;
    using Microsoft.Extensions.Logging;
    using Microsoft.Extensions.Options;
    using SampleMvcApp.Support;
    using System;
    using System.Security.Claims;
    using System.Threading.Tasks;
    
    namespace SampleMvcApp
    {
        public class Startup
    {
            public IConfiguration Configuration { get; }
            public Microsoft.AspNetCore.Hosting.IWebHostEnvironment HostingEnvironment { get; }
    
            public Startup(IConfiguration configuration, Microsoft.AspNetCore.Hosting.IWebHostEnvironment hostingEnvironment)
            {
                Configuration = configuration;
                HostingEnvironment = hostingEnvironment;
            }
            public void ConfigureServices(IServiceCollection services)
            {
                services.ConfigureSameSiteNoneCookies();
                services.AddMvc(options => options.EnableEndpointRouting = false);
    
                // Add authentication services
                services.AddAuthentication(options => {
                    options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                    options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                    options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                })
                .AddCookie()
                .AddOpenIdConnect("Auth0", options => {
                    // Set the authority to your Auth0 domain
                    options.Authority = $"https://{Configuration["Auth0:Domain"]}";
    
                    // Configure the Auth0 Client ID and Client Secret
                    options.ClientId = Configuration["Auth0:ClientId"];
                    options.ClientSecret = Configuration["Auth0:ClientSecret"];
    
                    // OpenIdConnectOptions
                    // Set response type to code
                    options.ResponseType = "code";
    
                    // Configure the scope
                    options.Scope.Clear();
                    options.Scope.Add("openid profile email"); // openid profile email
    
                    // Set the callback path, so Auth0 will call back to http://localhost:3000/callback
                    // Also ensure that you have added the URL as an Allowed Callback URL in your Auth0 dashboard
                    options.CallbackPath = new PathString("/callback");
    
                    // Configure the Claims Issuer to be Auth0
                    options.ClaimsIssuer = "Auth0";
    
                    // Saves tokens to the AuthenticationProperties
                    options.SaveTokens = true;
    
                    options.Events = new OpenIdConnectEvents
                    {
                        // handle the logout redirection 
                        // ASP.NET Core calls SignOutAsync for the "Auth0" authentication scheme. You need to provide the
                        // // OIDC middleware with the URL for logging the user out of Auth0. To set the URL,
                        // handle the OnRedirectToIdentityProviderForSignOut event when you register the OIDC authentication handler.
                        OnRedirectToIdentityProviderForSignOut = (context) =>
                        {
                            var logoutUri = $"https://{Configuration["Auth0:Domain"]}/v2/logout?client_id={Configuration["Auth0:ClientId"]}";
    
                            var postLogoutUri = context.Properties.RedirectUri;
                            if (!string.IsNullOrEmpty(postLogoutUri))
                            {
                                if (postLogoutUri.StartsWith("/"))
                                {
                                    // transform to absolute
                                    var request = context.Request;
                                    postLogoutUri = request.Scheme + "://" + request.Host + request.PathBase + postLogoutUri;
                                }
                                // When the application calls SignOutAsync for the OIDC middleware, it also calls the /v2/logout endpoint of
                                // the Auth0 Authentication API. The user is logged out of Auth0.
                                logoutUri += $"&returnTo={Uri.EscapeDataString(postLogoutUri)}";
                            }
    
                            context.Response.Redirect(logoutUri);
                            context.HandleResponse();
    
                            return Task.CompletedTask;
                        }
                    };
                });
    
                services.AddMvc()
                    .SetCompatibilityVersion(CompatibilityVersion.Version_3_0);
            }
    
            public void Configure(IApplicationBuilder app, Microsoft.AspNetCore.Hosting.IWebHostEnvironment env)
            {
                // env.EnvironmentName
                if (env.EnvironmentName == "Development")
                {
                    app.UseDeveloperExceptionPage();
                }
                else
                {
                    app.UseExceptionHandler("/Home/Error");
                    app.UseHsts();
                }
    
                app.UseStaticFiles();
                app.UseCookiePolicy();
    
                app.UseAuthentication();
                //app.UseMvc
    
                app.UseMvc(routes =>
                {
                    routes.MapRoute(
                        name: "default",
                        template: "{controller=Home}/{action=Index}/{id?}");
                });
            }
    
        }
    }

I am able to authenticate users using Auth0 now :).