Getting ArgumentOutOfRangeException error Idenity Server4 - identityserver4

We are using Entity framework core with Identity server4 and getting the ArgumentOutOfRangeException when calling the token endpoint via code. Here is our ConfigurationServices method in Identity server project:
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IConfiguration>(Configuration);
string connectionString = Configuration.GetConnectionString("IdentityServer");
var rsaProvider = new RSACryptoServiceProvider(512);
SecurityKey key = new RsaSecurityKey(rsaProvider);
var credentials = new Microsoft.IdentityModel.Tokens.SigningCredentials
(key, SecurityAlgorithms.RsaSha512Signature);
var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;
services.AddIdentityServer()
.AddSigningCredential(credentials)
// this adds the config data from DB (clients, resources)
.AddConfigurationStore(options =>
{
options.ConfigureDbContext = builder =>
builder.UseSqlServer(connectionString,
sql => sql.MigrationsAssembly(migrationsAssembly));
}) // this adds the operational data from DB (codes, tokens, consents)
.AddOperationalStore(options =>
{
options.ConfigureDbContext = builder =>
builder.UseSqlServer(connectionString,
sql => sql.MigrationsAssembly(migrationsAssembly));
// this enables automatic token cleanup. this is optional.
// options.EnableTokenCleanup = true;
// options.TokenCleanupInterval = 30;
});
// Add S3 to the ASP.NET Core dependency injection framework.
services.AddAWSService<Amazon.S3.IAmazonS3>();
}
Here is our client application that calling identity server project("http://localhost:3000/"):
[HttpGet]
[AllowAnonymous]
public async Task<IActionResult> Get(string client, string secret)
{
IActionResult result = null;
//discover endpoints from metadata
var disco = await DiscoveryClient.GetAsync("http://localhost:3000/");
if (disco.IsError)
{
result = NotFound(disco.Error);
return result;
}
//request token
var tokenClient = new TokenClient(disco.TokenEndpoint, client, secret);
var tokenResponse = await tokenClient.RequestClientCredentialsAsync(scope: "sup");
if (tokenResponse.IsError)
{
result = NotFound(tokenResponse.Error);
}
result = Ok(tokenResponse.Json);
return result;
}
Here is error we have got:

Related

CORS Policy Not Working in IdentityServer4

I am using IdentityServer4 (IS4) to connect to AzureAD for authentication. I have created the app on AzureAD and used the correct ClientID and Tenant ID as well.
I am getting the following error while signing in:
[15:13:04 Information] Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler
AuthenticationScheme: OpenIdConnect was challenged.
[15:13:06 Debug] IdentityServer4.Hosting.CorsPolicyProvider
CORS request made for path: /signin-oidc from origin: https://login.microsoftonline.com but was ignored because path was not for an allowed IdentityServer CORS endpoint
[15:13:06 Information] Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler
AuthenticationScheme: Identity.External signed in.
Please, I requesting to guide me, as in what is going wrong here.
Here's how my entire Startup.cs looks like:
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
using IdentityServer4;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.EntityFrameworkCore;
using IdentityServerHost.Quickstart.UI;
using System.Reflection;
using IdentityServer.Models;
using Microsoft.AspNetCore.Identity;
using IdentityServer.Data;
using IdentityServer4.Configuration;
using System;
using Microsoft.AspNetCore.Authentication;
using IdentityServer4.Services;
using Microsoft.Extensions.Logging;
using System.Collections.Generic;
namespace IdentityServer
{
public class Startup
{
public IWebHostEnvironment Environment { get; }
public IConfiguration Configuration { get; }
public Startup(IWebHostEnvironment environment, IConfiguration configuration)
{
Environment = environment;
Configuration = configuration;
}
public void ConfigureServices(IServiceCollection services)
{
var connectionString = Configuration.GetConnectionString("DefaultConnection");
var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;
services.AddControllersWithViews();
services.AddDbContext<IdentityServerContext>(options =>
options.UseMySql(connectionString, sql => sql.MigrationsAssembly(migrationsAssembly))
);
services.AddDbContext<Data.ConfigurationDbContext>(options => options.UseMySql(connectionString, sql => sql.MigrationsAssembly(migrationsAssembly)));
services.AddIdentity<ApplicationUser, IdentityRole>(options =>
{
options.SignIn.RequireConfirmedEmail = false;
//New added
options.Password.RequiredLength = 4;
options.Password.RequireLowercase = false;
options.Password.RequireUppercase = false;
options.Password.RequireDigit = false;
options.Password.RequireNonAlphanumeric = false;
options.Lockout.AllowedForNewUsers = true;
options.Lockout.DefaultLockoutTimeSpan = new TimeSpan(0, 15, 00);
options.Lockout.MaxFailedAccessAttempts = 5;
})
.AddEntityFrameworkStores<IdentityServerContext>()
.AddDefaultTokenProviders();
var builder = services.AddIdentityServer(options =>
{
options.Events.RaiseErrorEvents = true;
options.Events.RaiseInformationEvents = true;
options.Events.RaiseFailureEvents = true;
options.Events.RaiseSuccessEvents = true;
// see https://identityserver4.readthedocs.io/en/latest/topics/resources.html
options.EmitStaticAudienceClaim = true;
options.UserInteraction.LoginUrl = "/Account/Login";
options.UserInteraction.LogoutUrl = "/Account/Logout";
options.Authentication = new IdentityServer4.Configuration.AuthenticationOptions()
{
CookieLifetime = TimeSpan.FromHours(10), // ID server cookie timeout set to 10 hours
CookieSlidingExpiration = true
};
})
//.AddTestUsers(TestUsers.Users)
// this adds the config data from DB (clients, resources, CORS)
.AddConfigurationStore(options =>
{
options.ConfigureDbContext = builder => builder.UseMySql(connectionString, sql => sql.MigrationsAssembly(migrationsAssembly));
})
// this adds the operational data from DB (codes, tokens, consents)
.AddOperationalStore(options =>
{
options.ConfigureDbContext = builder => builder.UseMySql(connectionString, sql => sql.MigrationsAssembly(migrationsAssembly));
// this enables automatic token cleanup. this is optional.
options.EnableTokenCleanup = true;
})
.AddAspNetIdentity<ApplicationUser>()
.AddProfileService<IdentityProfileService>();
services.AddCors(options =>
{
options.AddPolicy("CorsPolicy",
builder => builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader());
});
var autBuilder = services.AddAuthentication();
//Azure AD
autBuilder.AddAzureAd(options => Configuration.Bind("AzureAd", options));
// not recommended for production - you need to store your key material somewhere secure
builder.AddDeveloperSigningCredential();
/*
services.AddAuthentication()
.AddGoogle(options =>
{
options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
// register your IdentityServer with Google at https://console.developers.google.com
// enable the Google+ API
// set the redirect URI to https://localhost:5001/signin-google
options.ClientId = "copy client ID from Google here";
options.ClientSecret = "copy client secret from Google here";
});
*/
}
public void Configure(IApplicationBuilder app)
{
if (Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
app.UseStaticFiles();
app.UseRouting();
app.UseCors("CorsPolicy");
app.UseIdentityServer();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapDefaultControllerRoute();
});
}
}
}
And the Azure Extension.cs
using System;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
namespace Microsoft.AspNetCore.Authentication
{
public static class AzureAdAuthenticationBuilderExtensions
{
public static AuthenticationBuilder AddAzureAd(this AuthenticationBuilder builder)
=> builder.AddAzureAd(_ => { });
public static AuthenticationBuilder AddAzureAd(this AuthenticationBuilder builder, Action<AzureAdOptions> configureOptions)
{
builder.Services.Configure(configureOptions);
builder.Services.AddSingleton<IConfigureOptions<OpenIdConnectOptions>, ConfigureAzureOptions>();
builder.AddOpenIdConnect();
return builder;
}
private class ConfigureAzureOptions: IConfigureNamedOptions<OpenIdConnectOptions>
{
private readonly AzureAdOptions _azureOptions;
public ConfigureAzureOptions(IOptions<AzureAdOptions> azureOptions)
{
_azureOptions = azureOptions.Value;
}
public void Configure(string name, OpenIdConnectOptions options)
{
options.ClientId = _azureOptions.ClientId;
options.Authority = $"{_azureOptions.Instance}{_azureOptions.TenantId}";
options.UseTokenLifetime = true;
options.CallbackPath = _azureOptions.CallbackPath;
options.RequireHttpsMetadata = false;
}
public void Configure(OpenIdConnectOptions options)
{
Configure(Options.DefaultName, options);
}
}
}
}
And the appsettings.json
Appsettings.json
{
"ConnectionStrings": {
//"DefaultConnection": "connectiong_string"
},
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"Domain": "",
"TenantId": "xxxxxxxxxxxxxxxxxxxxxxxxxx",
"ClientId": "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy",
"CallbackPath": "/signin-oidc"
},
"TimeSettings": {
"AbsoluteRefreshTokenLifetime": 15552000,
"SlidingRefreshTokenLifetime": 1296000,
"IdentityTokenLifetime": 300,
"AccessTokenLifetime": 300,
"AuthorizationCodeLifetime": 300
}
}
IdentityServer has its own CORS settings for requests made by its clients.
You use the AllowedCorsOrigins collection on the client configuration to set this up. Simply add the origin of the client to the collection and the default configuration in IdentityServer will consult these values to allow cross-origin calls from the origins.
new Client
{
...
AllowedCorsOrigins = new List<string>
{
"http://www.myclient.com"
}
}
Hard to tell, one thought is if the use of "CallbackPath": "/signin-oidc" should be changed to some other URL to not conflict with other things that uses /signin-oidc.
For example in the code here they use:
.AddOpenIdConnect("aad", "Sign-in with Azure AD", options =>
{
...
options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
options.SignOutScheme = IdentityServerConstants.SignoutScheme;
options.ResponseType = "id_token";
options.CallbackPath = "/signin-aad";
options.SignedOutCallbackPath = "/signout-callback-aad";
options.RemoteSignOutPath = "/signout-aad";

multiple configuration databases for IdentityServer4

Iam using an identityServer4 with multiple Databases. I could so far use muliple databases with the user-store. I solve it as the follwoing code of a middleware:
public async Task Invoke(HttpContext context)
{
var req = context.Request;
if (req.Path == "/Account/Login" && req.Method.Equals("POST"))
{
if (req.Form.Keys.Contains("Input.Database") == false)
{
throw new InvalidOperationException("No database key was sent with this request: " + req.Path);
}
var lDatabasKey = req.Form["Input.Database"];
_configuration["ConnectionStrings:default"] = _configuration[$"ConnectionStrings:{lDatabasKey}"];
}
the configuration Object get updated, so the value ConnectionString:default get updated with the connectionstring i need to use.
This concept unfortunatley not working the the configuration database, which inistalised in the ConfigureServices in Startup.cs:
string connectionString = Configuration.GetConnectionString("default");
services.AddIdentity<ApplicationUser, IdentityRole>(options =>
{
options.SignIn.RequireConfirmedEmail = false;
})
.AddEntityFrameworkStores<IdentityUserDbContext>()
.AddDefaultTokenProviders().AddClaimsPrincipalFactory<CentralHubClaimsPrincipalFactory>();
var builder = services.AddIdentityServer(options =>
{
options.Events.RaiseErrorEvents = true;
options.Events.RaiseInformationEvents = true;
options.Events.RaiseFailureEvents = true;
options.Events.RaiseSuccessEvents = true;
options.UserInteraction.LoginUrl = "/Account/Login";
options.UserInteraction.LogoutUrl = "/Account/Logout";
options.Authentication = new AuthenticationOptions()
{
CookieLifetime = TimeSpan.FromHours(10), // ID server cookie timeout set to 10 hours
CookieSlidingExpiration = true
};
})
.AddConfigurationStore(options =>
{
options.ConfigureDbContext = b => b.UseSqlServer(connectionString, sql => sql.MigrationsAssembly(migrationsAssembly));
})
.AddOperationalStore(options =>
{
options.ConfigureDbContext = b => b.UseSqlServer(connectionString, sql => sql.MigrationsAssembly(migrationsAssembly));
}).AddAspNetIdentity<ApplicationUser>()
.AddProfileService<AspNetIdentityProfileService>();
using breaking point i can see that the connectionString:default in the middleware has correct value of the database i want to use. but it still uses the default connectionString which has been saved in the previous method in startup.cs.
So is it possible to use multiple configuration databases for the identityServer?
One option is to create your own EntityFramework configuration backend for IdentityServer by taking the existing source code and hack the queries made.
Then use a clientID prefix as the "database" identifier/selector, like
A0000-A9999 -> goes to Database A
B0000-B9999 -> goes to Database B
C0000-C9999 -> goes to Database C
or use a clientID like:
AAA:XXX where AAA is the client/DB identifier and XXX is the client within that database.
To select the database/connection string to use. To "fool" IdentityServer to believe that there is only one "database".
Having a structured clientID also makes it easier to debug and reason about the system.

dotnet-core WebApp and multiple web api's access tokens using AzureB2C, MSAL

I have setup authentication/authorization for WebApp and Api and its working fine. The problem is when I have to introduce additional Api's which will be called from WebAPP.
The limitation is that you cannot ask a token with scopes mixing Web apis in one call. This is a limitation of the service (AAD), not of the library.
you have to ask a token for https://{tenant}.onmicrosoft.com/api1/read
and then you can acquire a token silently for https://{tenant}.onmicrosoft.com/api2/read as those are two different APIS.
I learned more about this from SO here and here
Since there is no full example other than couple of lines of code, I'm trying to find best way of implementing this solution.
Currently I have setup Authentication in Startup
services.AddAuthentication(sharedOptions =>
{
sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
sharedOptions.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
services.AddAzureAdB2C(options => Configuration.Bind("AzureAdB2C", options)).AddCookie();
AddAzureAdB2C is an customized extension method from Samples.
public static AuthenticationBuilder AddAzureAdB2C(this AuthenticationBuilder builder, Action<AzureAdB2COptions> configureOptions)
{
builder.Services.Configure(configureOptions);
builder.Services.AddSingleton<IConfigureOptions<OpenIdConnectOptions>, OpenIdConnectOptionsSetup>();
builder.AddOpenIdConnect();
return builder;
}
public class OpenIdConnectOptionsSetup : IConfigureNamedOptions<OpenIdConnectOptions>
{
public void Configure(OpenIdConnectOptions options)
{
options.ClientId = AzureAdB2COptions.ClientId;
options.Authority = AzureAdB2COptions.Authority;
options.UseTokenLifetime = true;
options.TokenValidationParameters = new TokenValidationParameters() { NameClaimType = "name" };
options.Events = new OpenIdConnectEvents()
{
OnRedirectToIdentityProvider = OnRedirectToIdentityProvider,
OnRemoteFailure = OnRemoteFailure,
OnAuthorizationCodeReceived = OnAuthorizationCodeReceived
};
}
public Task OnRedirectToIdentityProvider(RedirectContext context)
{
var defaultPolicy = AzureAdB2COptions.DefaultPolicy;
if (context.Properties.Items.TryGetValue(AzureAdB2COptions.PolicyAuthenticationProperty, out var policy) &&
!policy.Equals(defaultPolicy))
{
context.ProtocolMessage.Scope = OpenIdConnectScope.OpenIdProfile;
context.ProtocolMessage.ResponseType = OpenIdConnectResponseType.IdToken;
context.ProtocolMessage.IssuerAddress = context.ProtocolMessage.IssuerAddress.ToLower().Replace(defaultPolicy.ToLower(), policy.ToLower());
context.Properties.Items.Remove(AzureAdB2COptions.PolicyAuthenticationProperty);
}
else if (!string.IsNullOrEmpty(AzureAdB2COptions.ApiUrl))
{
context.ProtocolMessage.Scope += $" offline_access {AzureAdB2COptions.ApiScopes}";
context.ProtocolMessage.ResponseType = OpenIdConnectResponseType.CodeIdToken;
}
return Task.FromResult(0);
}
}
I guess the scope has to be set on this line for each API but this is part of pipeline.(in else if part of OnRedirectToIdentityProvide method above)
context.ProtocolMessage.Scope += $" offline_access {AzureAdB2COptions.ApiScopes}";
Following are api client configuration
services.AddHttpClient<IApiClient1, ApiClient1>()
.AddHttpMessageHandler<API1AccessTokenHandler>();
services.AddHttpClient<IApiClient2, ApiClient2>()
.AddHttpMessageHandler<API2AccessTokenHandler>();
Following is the code for acquiring token silently for API1.
public class API1AccessTokenHandler : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
IConfidentialClientApplication publicClientApplication = null;
try
{
// Retrieve the token with the specified scopes
scopes = AzureAdB2COptions.ApiScopes.Split(' ');
string signedInUserID = _httpContextAccessor.HttpContext.User.FindFirst(ClaimTypes.NameIdentifier).Value;
publicClientApplication = ConfidentialClientApplicationBuilder.Create(AzureAdB2COptions.ClientId)
.WithRedirectUri(AzureAdB2COptions.RedirectUri)
.WithClientSecret(AzureAdB2COptions.ClientSecret)
.WithB2CAuthority(AzureAdB2COptions.Authority)
.Build();
new MSALStaticCache(signedInUserID, _httpContextAccessor.HttpContext).EnablePersistence(publicClientApplication.UserTokenCache);
var accounts = await publicClientApplication.GetAccountsAsync();
result = await publicClientApplication.AcquireTokenSilent(scopes, accounts.FirstOrDefault())
.ExecuteAsync();
}
catch (MsalUiRequiredException ex)
{
}
if (result.AccessToken== null)
{
throw new Exception();
}
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
return await base.SendAsync(request, cancellationToken);
}
}
Following is the code for acquiring token silently for API2, API2AccessTokenHandler.
public class API2AccessTokenHandler : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
IConfidentialClientApplication publicClientApplication = null;
try
{
// Retrieve the token with the specified scopes
scopes = Constants.Api2Scopes.Split(' ');
string signedInUserID = _httpContextAccessor.HttpContext.User.FindFirst(ClaimTypes.NameIdentifier).Value;
publicClientApplication = ConfidentialClientApplicationBuilder.Create(AzureAdB2COptions.ClientId)
.WithRedirectUri(AzureAdB2COptions.RedirectUri)
.WithClientSecret(AzureAdB2COptions.ClientSecret)
.WithB2CAuthority(AzureAdB2COptions.Authority)
.Build();
new MSALStaticCache(signedInUserID, _httpContextAccessor.HttpContext).EnablePersistence(publicClientApplication.UserTokenCache);
var accounts = await publicClientApplication.GetAccountsAsync();
result = await publicClientApplication.AcquireTokenSilent(scopes, accounts.FirstOrDefault())
.ExecuteAsync();
}
catch (MsalUiRequiredException ex)
{
}
if (result.AccessToken== null)
{
throw new Exception();
}
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
return await base.SendAsync(request, cancellationToken);
}
}
Passing the scope while acquiring the token did not help. The token
is always null.
The account always have scope for Api1 but not for
Api2.
The scope of APi1 is added from the AzureB2COptions.ApiScope
as part of the ServiceCollection pipeline code in Startup.cs
I guess having separate calls to Acquire token is not helping in case of Api2 because scope is being set for Api1 in Startup.cs.
Please provide your valuable suggestions along with code samples.
UPDATE:
I'm looking something similar to WithExtraScopeToConsent which is designed for IPublicClientApplication.AcquireTokenInteractive. I need similar extension for ConfidentialClientApplicationBuilder to be used for AcquireTokenByAuthorizationCode
cca.AcquireTokenByAuthorizationCode(AzureAdB2COptions.ApiScopes.Split(' '), code)
.WithExtraScopeToConsent(additionalScopeForAPi2)
.ExecuteAsync();
Yes, we can have multiple scopes for same api not multiple scopes from different Apis.
In this sample, we retrieve the token with the specified scopes.
// Retrieve the token with the specified scopes
var scope = new string[] { api1_scope };
IConfidentialClientApplication cca = MsalAppBuilder.BuildConfidentialClientApplication();
var accounts = await cca.GetAccountsAsync();
AuthenticationResult result = await cca.AcquireTokenSilent(scope, accounts.FirstOrDefault()).ExecuteAsync();
var accessToken=result.AccessToken;
You can get the accessToken with different api scope.
// Retrieve the token with the specified scopes
var scope = new string[] { api2_scope };
IConfidentialClientApplication cca = MsalAppBuilder.BuildConfidentialClientApplication();
var accounts = await cca.GetAccountsAsync();
AuthenticationResult result = await cca.AcquireTokenSilent(scope, accounts.FirstOrDefault()).ExecuteAsync();
var accessToken=result.AccessToken;

Error connecting to http://localhost:8000/.well-known/openid-configuration/jwks. Object reference not set to an instance of an object

I host my identity server use address http://10.2.5.90:8000 and use nginx map https://10.2.5.90:8888 to http://10.2.5.90:8000.
When i tried to request discovery document like quickstart in client, "Error connecting to http://localhost:8000/.well-known/openid-configuration/jwks. Object reference not set to an instance of an object.." occurred.
I tried to change Issuer to https address and used customized DiscoveryDocumentRequest. But it was not work.
When I remove the nginx and access http://10.2.5.90:8000, It worked well.
IdentityServer:Startup.cs
public void ConfigureServices(IServiceCollection services)
{
// ...other codes
var builder = services.AddIdentityServer(options =>
{
options.Events.RaiseErrorEvents = true;
options.Events.RaiseInformationEvents = true;
options.Events.RaiseFailureEvents = true;
options.Events.RaiseSuccessEvents = true;
options.IssuerUri = "https://10.2.5.90:8888";
});
// ...other codes
}
Client: Program.cs
private static async Task<string> GetAccessTokenAsync()
{
var client = new HttpClient();
var req = new DiscoveryDocumentRequest
{
Address = "https://10.2.5.90:8888",
Policy = new DiscoveryPolicy
{
ValidateIssuerName = false,
ValidateEndpoints = false,
}
};
var disco = await client.GetDiscoveryDocumentAsync(req);
if (disco.IsError)
{
Console.WriteLine(disco.Error);
// output: Error connecting to http://localhost:8000/.well-known/openid-configuration/jwks. Object reference not set to an instance of an object..
return null;
}
// ...other codes
}
Edit:
I changed the code when config identity server and it works when running discovery.
var builder = services.AddIdentityServer(options =>
{
options.PublicOrigin = "https://10.2.5.90:8888";
});
However, I still couldn't access my api. The error is Exception occurred while processing message.IDX20803: Unable to obtain configuration from: 'http://localhost:8000/.well-known/openid-configuration' and I'm researchig the solution
You have to change de Authority property in your api. The api needs to access to the discovery endpoint through nginx (port 8888):
services.AddAuthentication("Bearer")
.AddJwtBearer(options =>
{
options.Audience = "api1";
options.RequireHttpsMetadata = true;
options.Authority = "https://10.2.5.90:8888";
});
If you have a public IP and your backend farm use internal uris you can adjust your host uri data in the middleware. Try to put this middleware in the first position:
app.Use(async (context, next) =>
{
context.Request.Scheme = "https";
context.Request.Host = new HostString("10.2.5.90.8888");
context.Request.PathBase = "yourApplicationPathBase";
await next.Invoke();
});
Of course, you have to parameterize this strings by environment in your configuration.

Error while calling DiscoveryClient.GetAsync connect token endpoint

We have deployed the identity server4 as a aws serverless lambda function. But when we are calling the base authorize url from code(while creating token for client) getting the forbidden error. Here is the code:
[HttpGet]
[AllowAnonymous]
public async Task<IActionResult> Get(string client, string secret)
{
IActionResult result = null;
//discover endpoints from metadata
var disco = await DiscoveryClient.GetAsync("https://hide-for-security-reasons/prod/");
if (disco.IsError)
{
result = NotFound(disco.Error);
return result;
}
//request token
var tokenClient = new TokenClient(disco.TokenEndpoint, client, secret);
var tokenResponse = await tokenClient.RequestClientCredentialsAsync(scope: "sup");
if (tokenResponse.IsError)
{
result = NotFound(tokenResponse.Error);
}
result = Ok(tokenResponse.Json);
return result;
}

Resources