{"id":23109389,"url":"https://github.com/sangeethnandakumar/express-authentication-template","last_synced_at":"2026-05-19T14:07:32.193Z","repository":{"id":142980243,"uuid":"286113612","full_name":"sangeethnandakumar/Express-Authentication-Template","owner":"sangeethnandakumar","description":"This repository holds an example template structure for securing ASP.NET WebApi's with Identity Server 4","archived":false,"fork":false,"pushed_at":"2020-08-08T22:05:49.000Z","size":1215,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-10-10T07:08:47.839Z","etag":null,"topics":["aspnetidentity","client-credentials-grant","entityframeworkcore","identity","identityserver4","resource-owner-password-credentials","sql-server"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sangeethnandakumar.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2020-08-08T20:20:21.000Z","updated_at":"2020-08-16T16:09:00.000Z","dependencies_parsed_at":"2023-04-07T04:02:31.220Z","dependency_job_id":null,"html_url":"https://github.com/sangeethnandakumar/Express-Authentication-Template","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/sangeethnandakumar/Express-Authentication-Template","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sangeethnandakumar%2FExpress-Authentication-Template","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sangeethnandakumar%2FExpress-Authentication-Template/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sangeethnandakumar%2FExpress-Authentication-Template/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sangeethnandakumar%2FExpress-Authentication-Template/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sangeethnandakumar","download_url":"https://codeload.github.com/sangeethnandakumar/Express-Authentication-Template/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sangeethnandakumar%2FExpress-Authentication-Template/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33219435,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-19T07:54:09.561Z","status":"ssl_error","status_checked_at":"2026-05-19T07:54:08.508Z","response_time":58,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aspnetidentity","client-credentials-grant","entityframeworkcore","identity","identityserver4","resource-owner-password-credentials","sql-server"],"created_at":"2024-12-17T01:35:59.795Z","updated_at":"2026-05-19T14:07:32.186Z","avatar_url":"https://github.com/sangeethnandakumar.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"## API To API Communication\nAPI to API Connection is federated through Identity Server. We are using Client Credential bearer token authentication model for this. For this we need to create 2 API projects. Let's say API-A and API-B. Then we need to create an Identity Server to sit in the middle and federate secure access. \n\u003e We need to communicate to an endpoint in API-B from API-A\n### Configure API Project A\nCreate a new ASP.NET Core WebAPI Project. We call it it API-A\n### Configure API Project B\nCreate a new ASP.NET Core WebAPI Project. We call it it API-B\n### Configure Identity Server\nCreate a new ASP.NET Core MVC Project. We call it it Identity Server\n\n\n---\n# CONFIGURE IDENTITY SERVER\nCreate a new ASP.NET Core MVC Project. We call it it Identity Server\n#### Install NuGet Packages\n```text\nIdentityServer4\nIdentityServer4.AspNetIdentity\nMicrosoft.AspNetCore.Identity.EntityFrameworkCore\nMicrosoft.EntityFrameworkCore\nMicrosoft.EntityFrameworkCore.Design\nMicrosoft.EntityFrameworkCore.SqlServer\n```\nPackage | Why we are using it?\n------------ | -------------\nIdentityServer4 | This is the core library Identity Server 4 \nIdentityServer4.AspNetIdentity | There are lot of ways to store user info on our application. The secure and recomended way is to use AspNetIdentity system\nMicrosoft.EntityFrameworkCore | We are using EF Core 6 to access our databases\nMicrosoft.AspNetCore.Identity.EntityFrameworkCore | EF Core 6 support for AspNEtCore Identity\nMicrosoft.EntityFrameworkCore.Design | This is a design component required for EF Core 6 migrations and more\nMicrosoft.EntityFrameworkCore.SqlServer | EF 6 Core Support for SQL Server. We are going to store our data on an SQL Server database\n#### Configure AppSettings.json\n```json\n{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\",\n      \"Microsoft\": \"Warning\",\n      \"Microsoft.Hosting.Lifetime\": \"Information\"\n    }\n  },\n\n  \"AllowedHosts\": \"*\",\n\n  \"ConnectionStrings\": {\n    \"TIS\": \"Server=DB_SERVER;Database=DATABASE;Trusted_Connection=True;\"\n  },\n\n  \"IdentityServer\": {\n    \"Scopes\": [ \"ScxWebApi\", \"ScxWebApiDev\" ],\n    \"Resources\": [\n      {\n        \"Name\": \"ScxWebApi\",\n        \"DisplayName\": \"Production Web API\",\n        \"Scopes\": [ \"ScxWebApi\" ]\n      },\n      {\n        \"Name\": \"ScxWebApiDev\",\n        \"DisplayName\": \"Development Web API\",\n        \"Scopes\": [ \"ScxWebApiDev\" ]\n      }\n    ],\n    \"Clients\": [\n      {\n        \"Name\": \"Postman Client\",\n        \"ClientId\": \"admin\",\n        \"ClientSecrets\": [ \"admin123\" ],\n        \"Scopes\": [ \"ScxWebApi\", \"ScxWebApiDev\" ],\n        \"GrandType\": \"ClientCredentials\"\n      },\n\n      {\n        \"Name\": \"Mobile Client\",\n        \"ClientId\": \"sangee\",\n        \"ClientSecrets\": [ \"sangee123\" ],\n        \"Scopes\": [ \"ScxWebApi\", \"ScxWebApiDev\" ],\n        \"GrandType\": \"ResourceOwnerPasswordAndClientCredentials\"\n      }\n    ]\n  }\n\n}\n\n```\nOptions | Why we are using it?\n------------ | -------------\nConnectionStrings | Connection String to work with EF 6 Core\nIdentityServer -- Scopes | An array of all scopes (API Names) our Identity Server 4 need to handle\nIdentityServer -- Resources | A list of resources (API Infos) to be configured with Identity Server 4\nIdentityServer -- Clients | A list of clients and their allowed scopes and token mechanism\n#### Setup Startup.cs\n```csharp\npublic void ConfigureServices(IServiceCollection services)\n        {\n            //Configure EF6\n            services.AddDbContext\u003cAppDbContext\u003e(config =\u003e\n            {\n                config.UseSqlServer(Configuration.GetConnectionString(\"TIS\"));\n            });\n\n            //Configure Identity\n            services.AddIdentity\u003cIdentityUser, IdentityRole\u003e(config =\u003e\n            {\n                config.Password.RequiredLength = 4;\n                config.Password.RequireDigit = false;\n                config.Password.RequiredUniqueChars = 0;\n                config.Password.RequireNonAlphanumeric = false;\n                config.Password.RequireUppercase = false;\n                config.SignIn.RequireConfirmedEmail = false;\n            })                \n                .AddEntityFrameworkStores\u003cAppDbContext\u003e()\n                .AddDefaultTokenProviders();\n\n            //Configure IdentityServer\n            services.AddIdentityServer()\n                .AddInMemoryApiResources(Config.GetApiResources(Configuration))\n                .AddInMemoryClients(Config.GetApiClients(Configuration))\n                .AddInMemoryApiScopes(Config.GetApiScopes(Configuration))\n                .AddDeveloperSigningCredential()\n                .AddAspNetIdentity\u003cIdentityUser\u003e()\n                .AddCustomResourceOwnerPasswordValidaton();\n\n            services.AddControllersWithViews();\n        }\n        \n        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)\n        {\n            app.UseHttpsRedirection();\n            app.UseStaticFiles();\n            app.UseRouting();\n            \n            //Use Identity Servr\n            app.UseIdentityServer();\n\n            app.UseEndpoints(endpoints =\u003e\n            {\n                endpoints.MapControllerRoute(\n                    name: \"default\",\n                    pattern: \"{controller=Home}/{action=Index}/{id?}\");\n            });\n        }\n```\n#### Identity Server Configurations\nNow we need to grab contents from AppSettings.json to be provided to Identity Server 4 in meaningfull format. Let's create a model similar to AppSettings.json provided above for parsing\n```csharp\nnamespace IdentityServer.Configurations.Configs\n{\n    public class IdentityAppSettings\n    {\n        public List\u003cIdentityResources\u003e Resources { get; set; }\n        public List\u003cstring\u003e Scopes { get; set; }\n        public List\u003cIdentityClient\u003e Clients { get; set; }\n    }\n\n    public class IdentityResources\n    {\n        public string Name { get; set; }\n        public string DisplayName { get; set; }\n        public List\u003cstring\u003e Scopes { get; set; }\n    }\n\n    public class IdentityClient\n    {\n        public string Name { get; set; }\n        public string ClientId { get; set; }\n        public List\u003cstring\u003e ClientSecrets { get; set; }\n        public string GrandType { get; set; }\n        public List\u003cstring\u003e Scopes { get; set; }\n    }\n}\n```\n#### Identity Server Configurations II\nNow let's create a class that parses AppSettings.json and exposes config endpoints to be used in Startup.cs\n```csharp\nnamespace IdentityServer.Configurations.Configs\n{\n    public static class Config\n    {\n\n        public static IEnumerable\u003cApiResource\u003e GetApiResources(IConfiguration config)\n        {\n            var appsettingsResources = config.GetSection(\"IdentityServer:Resources\").Get\u003cIEnumerable\u003cIdentityResources\u003e\u003e();\n            var resources = new List\u003cApiResource\u003e();\n            foreach (var res in appsettingsResources)\n            {\n                resources.Add(new ApiResource(res.Name, res.DisplayName) { Scopes = res.Scopes });\n            }\n            return resources;\n        }\n\n        public static IEnumerable\u003cClient\u003e GetApiClients(IConfiguration config)\n        {\n            var appsettingsClients = config.GetSection(\"IdentityServer:Clients\").Get\u003cIEnumerable\u003cIdentityClient\u003e\u003e();\n            var clients = new List\u003cClient\u003e();\n            foreach (var client in appsettingsClients)\n            {\n                var grandType = GrantTypes.ResourceOwnerPasswordAndClientCredentials;\n                switch (client.GrandType)\n                {\n                    case \"ResourceOwnerPasswordAndClientCredentials\":\n                        grandType = GrantTypes.ResourceOwnerPasswordAndClientCredentials;\n                        break;\n                    case \"ClientCredentials\":\n                        grandType = GrantTypes.ResourceOwnerPasswordAndClientCredentials;\n                        break;\n                } \n                var clientSecrets = new List\u003cSecret\u003e();\n                foreach(var secret in client.ClientSecrets)\n                {\n                    clientSecrets.Add(new Secret(secret.Sha256()));\n                }\n                clients.Add(new Client\n                {\n                    ClientId = client.ClientId,\n                    ClientSecrets = clientSecrets,\n                    AllowedScopes = client.Scopes,\n                    AllowedGrantTypes = grandType,\n                    AccessTokenType = AccessTokenType.Jwt,\n                    AccessTokenLifetime = 120,\n                    IdentityTokenLifetime = 120,\n                    UpdateAccessTokenClaimsOnRefresh = true,\n                    SlidingRefreshTokenLifetime = 30,\n                    AllowOfflineAccess = true,\n                    RefreshTokenExpiration = TokenExpiration.Absolute,\n                    RefreshTokenUsage = TokenUsage.OneTimeOnly,\n                    AlwaysSendClientClaims = true,\n                    Enabled = true,\n                });\n            }\n            return clients;\n        }\n\n        public static IEnumerable\u003cApiScope\u003e GetApiScopes(IConfiguration config)\n        {\n            var appsettingsScopes = config.GetSection(\"IdentityServer:Scopes\").Get\u003cIEnumerable\u003cstring\u003e\u003e();\n            var scopes = new List\u003cApiScope\u003e();\n            foreach (var scope in appsettingsScopes)\n            {\n                scopes.Add(new ApiScope(scope));\n            }\n            return scopes;\n        }\n\n    }\n}\n```\n#### Setup Entity Framework Core 6\nNow create a DbContext class for EF 6 to operate\n```csharp\nnamespace IdentityServer.Configurations.EF\n{\n    public class AppDbContext : IdentityDbContext\n    {\n        public AppDbContext(DbContextOptions\u003cAppDbContext\u003e options) : base(options)\n        {\n        }\n    }\n}\n\n```\n#### OverRide Resource Owner Password Validation Extension Methord\nNow we are going to implement custom \"Resource Owner Password\" validatior. There we try to check if the user is logged in or not using AspNet Identity. Let's create an extention methord that can be attached to IdentityServer builder in Startup.cs file\n```csharp\nnamespace IdentityServer.Configurations.IdentityOverrides\n{\n    public static class ResourceOwnerPasswordValidatonExtension\n    {\n        public static IIdentityServerBuilder AddCustomResourceOwnerPasswordValidaton(this IIdentityServerBuilder builder)\n        {\n            builder.AddProfileService\u003cProfileService\u003e();\n            builder.AddResourceOwnerValidator\u003cResourceOwnerPasswordValidator\u003e();\n            return builder;\n        }\n    }\n}\n```\n#### Implement OverRide Resource Owner Password Validatior\nLet's Implement validator and profile service used by Identity Server 4\n```csharp\nnamespace IdentityServer.Configurations.IdentityOverrides\n{\n    public class ResourceOwnerPasswordValidator : IResourceOwnerPasswordValidator\n    {\n        private readonly UserManager\u003cIdentityUser\u003e _userManager;\n        private readonly SignInManager\u003cIdentityUser\u003e _signinManager;\n        private readonly RoleManager\u003cIdentityRole\u003e _roleManager;\n\n        public ResourceOwnerPasswordValidator(UserManager\u003cIdentityUser\u003e userManager, SignInManager\u003cIdentityUser\u003e signinManager, RoleManager\u003cIdentityRole\u003e roleManager)\n        {\n            _userManager = userManager;\n            _signinManager = signinManager;\n            _roleManager = roleManager;\n        }\n\n        public async Task ValidateAsync(ResourceOwnerPasswordValidationContext context)\n        {\n            //Custom Validation\n            var user = await _userManager.FindByNameAsync(context.UserName);\n            if (user != null)\n            {\n                try\n                {\n                    var isLoggedIn = await _signinManager.PasswordSignInAsync(user, context.Password, false, lockoutOnFailure: false);\n                    if (isLoggedIn.Succeeded)\n                    {\n                        context.Result = new GrantValidationResult(user.Id, OidcConstants.AuthenticationMethods.Password);\n                    }\n                }\n                catch (Exception ex)\n                {\n                    Console.WriteLine(ex.ToString());\n                }\n            }\n        }\n    }\n}\n```\n#### Create Profile Service\nWe also need to create a profile service override\n```csharp\nnamespace IdentityServer.Configurations.IdentityOverrides\n{\n    public class ProfileService : IProfileService\n    {\n        private readonly UserManager\u003cIdentityUser\u003e _userManager;\n\n        public ProfileService(UserManager\u003cIdentityUser\u003e userManager)\n        {\n            _userManager = userManager;\n        }\n\n        public async Task GetProfileDataAsync(ProfileDataRequestContext context)\n        {\n            var id = context.Subject.GetSubjectId();\n            var user = await _userManager.FindByIdAsync(id);\n            var claims = await _userManager.GetClaimsAsync(user) as List\u003cClaim\u003e;\n            claims.Add(new Claim(\"username\", user.UserName));\n            context.IssuedClaims = claims;\n        }\n\n        public async Task IsActiveAsync(IsActiveContext context)\n        {\n            var sub = context.Subject.GetSubjectId();\n            var user = _userManager.FindByIdAsync(context.Subject.GetSubjectId());\n            context.IsActive = user != null;\n        }\n    }\n}\n```\n---\n# EntityFramework 6 MIGRATION\nMigration is required for persisting AspNetIdenity entries.\n1. We need to install Entity Framework Core 6 first. For that run the command `dotnet tool install --global dotnet-ef`\n2. Create a migration by going to the project folder and run `dotnet ef migrations add FirstMigration`\n3. Wait for build to finish\n4. Update database by running `dotnet ef database update`\n\n---\n# CONFIGURE API-A\nCreate a new ASP.NET Core API Project. We call it it APIA\n#### Install NuGet Packages\n```text\nMicrosoft.AspNetCore.Authentication.JwtBearer\nMicrosoft.AspNet.Identity.Core\nMicrosoft.AspNetCore.Identity.EntityFrameworkCore\nMicrosoft.EntityFrameworkCore\nMicrosoft.EntityFrameworkCore.Design\nMicrosoft.EntityFrameworkCore.SqlServer\n```\n### Configure AppSettings.json\nAdd Authority \u0026 Audiance on API\n```json\n{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\",\n      \"Microsoft\": \"Warning\",\n      \"Microsoft.Hosting.Lifetime\": \"Information\"\n    }\n  },\n  \"AllowedHosts\": \"*\",\n\n  \"ConnectionStrings\": {\n    \"TIS\": \"Server=DESKTOP-708EN4A\\\\SQLEXPRESS;Database=TIS;Trusted_Connection=True;\"\n  },\n\n  \"Security\": {\n    \"IdentityServer\": {\n      \"Authority\": \"https://localhost:44393/\",\n      \"Audiance\": \"ScxWebApi\"\n    }\n  }\n}\n```\n### Setup Startup.cs\nSetup Startup.cs to work with Identity And EF 6\n```csharp\npublic void ConfigureServices(IServiceCollection services)\n        {\n            //Configure EF6\n            services.AddDbContext\u003cAppDbContext\u003e(config =\u003e\n            {\n                config.UseSqlServer(Configuration.GetConnectionString(\"TIS\"));\n            });\n\n            //Configure Identity\n            services.AddIdentity\u003cIdentityUser, IdentityRole\u003e(config =\u003e\n            {\n                config.Password.RequiredLength = 4;\n                config.Password.RequireDigit = false;\n                config.Password.RequiredUniqueChars = 0;\n                config.Password.RequireNonAlphanumeric = false;\n                config.Password.RequireUppercase = false;\n                config.SignIn.RequireConfirmedEmail = false;\n            })\n                .AddEntityFrameworkStores\u003cAppDbContext\u003e()\n                .AddDefaultTokenProviders();\n\n            //Identity Server Configuration\n            var identityAuthority = Configuration.GetSection(\"Security:IdentityServer:Authority\").Value;\n            var identityScope = Configuration.GetSection(\"Security:IdentityServer:Audiance\").Value;\n            services.AddAuthentication(options =\u003e\n            {\n                options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;\n                options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;\n                options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;\n            }).AddJwtBearer(\"Bearer\", config =\u003e\n            {\n                config.Authority = identityAuthority;\n                config.TokenValidationParameters = new TokenValidationParameters\n                {\n                    ValidateAudience = true\n                };\n                config.Audience = identityScope;\n            });\n            \n            services.AddControllersWithViews();\n        }\n        \n        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)\n        {\n            app.UseHttpsRedirection();\n            app.UseStaticFiles();\n\n            app.UseRouting();\n\n            app.UseAuthentication();\n            app.UseAuthorization();\n\n            app.UseEndpoints(endpoints =\u003e\n            {\n                endpoints.MapControllerRoute(\n                    name: \"default\",\n                    pattern: \"{controller=Home}/{action=Index}/{id?}\");\n            });\n        }\n```\n### Add DbContext class\nAdd a DBContext class to work with EF 6\n*Also don't forget to add custom classes for these table declarations. They are used for EF 6 migrations and ORM mappings, LINQ and quering DB\n```csharp\nnamespace APIA.EF\n{\n    public class AppDbContext : IdentityDbContext\n    {\n        public AppDbContext(DbContextOptions\u003cAppDbContext\u003e options) : base(options)\n        {\n        }\n\n        //Required database tables can come below as DbSet\u003cT\u003e\n    }\n}\n```\n### Controller\nUsing the HttpContext you will get the logged in user's details\n```csharp\nnamespace APIA.Controllers\n{\n    public class HomeController : Controller\n    {\n        private readonly UserManager\u003cIdentityUser\u003e _userManager;\n\n        public HomeController(UserManager\u003cIdentityUser\u003e userManager)\n        {\n            _userManager = userManager;\n        }\n\n        public IActionResult Index()\n        {\n            return View();\n        }\n\n        [Authorize]\n        public async Task\u003cIActionResult\u003e OpenBox()\n        {\n            // We will get all inoformations of logged in user here including claims\n            var userInfo = await _userManager.GetUserAsync(HttpContext.User);\n            return Ok(\"Yeahhh\");\n        }\n    }\n}\n```\n\u003e From this implementation (`_userManager.GetUserAsync(HttpContext.User);`). You will get information about the logged in client if he iuses ResourceOwner password validaton as GrandType\n---\n# CONFIGURE API-B\nLets configure API-B that can be used to call API-A. Most of the configurations are same. Let's create another WebAPI project that we can call APIB\n#### Install NuGet Packages\n```text\nMicrosoft.AspNetCore.Authentication.JwtBearer\nIdentityModel\n```\n## AppSettings.json\n```json\n{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\",\n      \"Microsoft\": \"Warning\",\n      \"Microsoft.Hosting.Lifetime\": \"Information\"\n    }\n  },\n\n  \"AllowedHosts\": \"*\",\n\n  \"Security\": {\n    \"IdentityServer\": {\n      \"Authority\": \"https://localhost:44393/\",\n      \"Audiance\": \"ScxWebApiDev\"\n    }\n  }\n}\n```\n## Startup.cs\nIn this API we are not using ASPNet Identity\n```csharp\n public void ConfigureServices(IServiceCollection services)\n        {\n            //Identity Server Configuration\n            var identityAuthority = Configuration.GetSection(\"Security:IdentityServer:Authority\").Value;\n            var identityScope = Configuration.GetSection(\"Security:IdentityServer:Audiance\").Value;\n            services.AddAuthentication(\"Bearer\").AddJwtBearer(\"Bearer\", config =\u003e\n            {\n                config.Authority = identityAuthority;\n                config.TokenValidationParameters = new TokenValidationParameters\n                {\n                    ValidateAudience = true\n                };\n                config.Audience = identityScope;\n            });\n\n            services.AddHttpClient();\n            services.AddControllersWithViews();\n        }\n\n        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)\n        {\n            app.UseHttpsRedirection();\n            app.UseStaticFiles();\n\n            app.UseRouting();\n\n            app.UseAuthentication();\n            app.UseAuthorization();\n\n            app.UseEndpoints(endpoints =\u003e\n            {\n                endpoints.MapControllerRoute(\n                    name: \"default\",\n                    pattern: \"{controller=Home}/{action=Index}/{id?}\");\n            });\n        }\n```\n### Call API-A from API-B\n```csharp\nnamespace APIB.Controllers\n{\n    public class HomeController : Controller\n    {\n        private readonly IHttpClientFactory _httpClient;\n\n        public HomeController(IHttpClientFactory httpClient)\n        {\n            _httpClient = httpClient;\n        }\n\n        public IActionResult Index()\n        {\n            return View();\n        }\n\n        public async Task\u003cIActionResult\u003e ShowSecret()\n        {\n            var authClient = _httpClient.CreateClient();\n            var discoveryDocument = await authClient.GetDiscoveryDocumentAsync(\"https://localhost:44393/\");\n            var tokenResponse = await authClient.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest\n            {\n                Address = discoveryDocument.TokenEndpoint,\n                ClientId = \"admin\",\n                ClientSecret = \"admin123\",\n                Scope = \"ScxWebApi\"\n            });\n            var apiClient = _httpClient.CreateClient();\n            apiClient.SetBearerToken(tokenResponse.AccessToken);\n            var response = await apiClient.GetAsync(\"https://localhost:44354/Home/Secret\");\n            var content = await response.Content.ReadAsStringAsync();\n            return View();\n        }\n    }\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsangeethnandakumar%2Fexpress-authentication-template","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsangeethnandakumar%2Fexpress-authentication-template","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsangeethnandakumar%2Fexpress-authentication-template/lists"}