Call Api from blazor and pass Auth token - azure-active-directory

I have a blazor webassembly project that gets created from https://github.com/Azure-Samples/ms-identity-blazor-wasm/tree/main/WebApp-graph-user/Call-MSGraph.
Its basically the project that gets created when you use the .net core template for a Blazor application that uses authentication via AD B2B
dotnet new blazorwasm -au SingleOrg --client-id "{CLIENT ID}" -o {APP NAME} --tenant-id "{TENANT ID}"
I was then able to call graph.api when the user logged in. I then tried to call my own Api with that authentication as described in https://learn.microsoft.com/en-us/aspnet/core/blazor/security/webassembly/additional-scenarios?view=aspnetcore-3.1.
I used
builder.Services.AddHttpClient<ITestDataService, TestDataService>(
client => client.BaseAddress = new Uri("https://localhost:44342/"))
.AddHttpMessageHandler(x =>
{
var handler = x.GetRequiredService<AuthorizationMessageHandler>()
.ConfigureHandler(new[] { "https://localhost:44342/" },
scopes: new[] { "https://graph.microsoft.com/User.Read" });
return handler;
});
I can see that a token is attached when calling the Api but authentication fails (401). The api is generated from Visual Studio templates for B2B AD and uses the configuration that is also used for the Blazor application.
This is its Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(AzureADDefaults.BearerAuthenticationScheme)
.AddAzureADBearer(options => Configuration.Bind("AzureAd", options));
services.AddControllers();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseCors(policy =>
policy.WithOrigins("http://localhost:5000",
"https://localhost:5001")
.AllowAnyMethod()
.WithHeaders(HeaderNames.ContentType,
HeaderNames.Authorization,
"x-custom-header")
.AllowCredentials());
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
Do you have any idea what is missing?
The complete source is available at github https://github.com/mathiasfritsch/blazor-calls-api

If you want to call Microsoft graph and your custom API in one blazor webassembly project, we can implement it by creating different HTTP client to call different API
For example
Register a server API app
Register an AAD app for the Server API app
Expose an API
Register a client app
Register a client app
Enable Implicit grant flow
Add API permissions. (Graph API permissions and API app permissions)
Configure API app
Please add the following code in Startup.cs
public void ConfigureServices(IServiceCollection services)
{
JwtSecurityTokenHandler.DefaultMapInboundClaims = false;
services.AddCors(options =>
{
options.AddDefaultPolicy(
builder => builder.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod());
});
services.AddAuthentication(AzureADDefaults.BearerAuthenticationScheme)
.AddAzureADBearer(options => Configuration.Bind("AzureAd", options));
services.Configure<JwtBearerOptions>(AzureADDefaults.JwtBearerAuthenticationScheme, options =>
{
options.Authority += "/v2.0";
options.TokenValidationParameters = new TokenValidationParameters
{
ValidIssuers = new[] {
$"https://sts.windows.net/{Configuration["AzureAD:TenantId"]}/",
$"https://login.microsoftonline.com/{Configuration["AzureAD:TenantId"]}/v2.0"
},
RoleClaimType = "roles",
// The web API accepts as audiences both the Client ID (options.Audience) and api://{ClientID}.
ValidAudiences = new[]
{
options.Audience,
$"api://{options.Audience}"
}
};
});
....
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.OAuthClientId(Configuration["Swagger:ClientId"]);
c.OAuthScopeSeparator(" ");
c.OAuthAppName("Protected Api");
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
});
app.UseHttpsRedirection();
app.UseRouting();
app.UseCors();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
Configure Client APP
Create custom AuthorizationMessageHandler for Graph API and custom API
// custom API
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
public class CustomAuthorizationMessageHandler : AuthorizationMessageHandler
{
public CustomAuthorizationMessageHandler(IAccessTokenProvider provider,
NavigationManager navigationManager)
: base(provider, navigationManager)
{
ConfigureHandler(
authorizedUrls: new[] { "https://localhost:44300/" },
scopes: new[] { "the API app scope" });
}
}
//Graph API
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
public class GraphAuthorizationMessageHandler : AuthorizationMessageHandler
{
public GraphAuthorizationMessageHandler(IAccessTokenProvider provider,
NavigationManager navigationManager)
: base(provider, navigationManager)
{
ConfigureHandler(
authorizedUrls: new[] { "https://graph.microsoft.com/" },
scopes: new[] { "https://graph.microsoft.com/User.Read" });
}
}
Add the following code to the program.cs
public class Program
{
public static async Task Main(string[] args)
{
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("app");
builder.Services.AddScoped<CustomAuthorizationMessageHandler>();
builder.Services.AddScoped<GraphAuthorizationMessageHandler>();
// register HTTP client to call our own api
builder.Services.AddHttpClient("MyAPI", client => client.BaseAddress = new Uri("https://localhost:44300/"))
.AddHttpMessageHandler<CustomAuthorizationMessageHandler>();
// register HTTP client to call graph api
builder.Services.AddHttpClient("GraphAPI", client => client.BaseAddress = new Uri("https://graph.microsoft.com/"))
.AddHttpMessageHandler<GraphAuthorizationMessageHandler>();
builder.Services.AddMsalAuthentication(options =>
{
builder.Configuration.Bind("AzureAd", options.ProviderOptions.Authentication);
options.ProviderOptions.DefaultAccessTokenScopes.Add("<the API app scope>");
options.ProviderOptions.AdditionalScopesToConsent.Add("https://graph.microsoft.com/User.Read");
});
await builder.Build().RunAsync();
}
}
Call the api
#inject IHttpClientFactory _clientFactory
var httpClient = _clientFactory.CreateClient("<the client name you register>");
await apiClient.GetStringAsync("path");

Related

Unable to consume .NET Core web API in React JS After Single Sign on using Azure Ad

I have successfully implemented Single Sign on with Azure Ad and fetched profile using MS Graph API but when I try to consume my dot net web API it is showing me error Unauthorized(401)
May be I am missing something in configuration,
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"Domain": "example.onmicrosoft.com",
"ClientId": "392xxxx2-bxx4-4xxf-axxc-505bd9c6d8b4",
"TenantId": "06xxx2xbe-9xxe-4xx8-bxxd-e1a6ebxxxxd",
"scopes": "api://3xxxxe52-bxx4-4xxf-axx2c-505bxxxxb4/User.Read"
}
here is my Startup.cs code
using AutoMapper;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.OpenApi.Models;
using TMS.API.Configuration;
using TMS.DAL.Configuration;
using TMS.DAL.Mapper;
using Microsoft.Identity.Web;
namespace TMS.API
{
public class Startup
{
public Startup(IConfiguration configuration) => Configuration = configuration;
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddMicrosoftIdentityWebApi(Configuration, "AzureAd");
services.AddControllers();
services.AddSwaggerGen(s =>
{
s.SwaggerDoc("v1", new OpenApiInfo() { Title = "TMS API", Version = "V1" });
});
services.AddAutoMapper(typeof(Startup));
services.Configure<Setting>(Configuration.GetSection("Settings"));
services.RegisterEngineServices();
services.RegisterRepositories();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
app.UseCors(x => x
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.WithHeaders()
.WithExposedHeaders());
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "TMS v1");
});
}
private static void AddAutoMapper(IServiceCollection services)
{
var mapperConfig = new MapperConfiguration(mc =>
{
mc.AddProfile(new BSRMapperClass());
});
IMapper mapper = mapperConfig.CreateMapper();
services.AddSingleton(mapper);
}
}
}
Controller:
[Route("api/[controller]")]
[ApiController]
[RequiredScope(RequiredScopesConfigurationKey ="AzureAd:scopes")]
public class GeneralController : ControllerBase
{
private readonly IConfiguration _configuration;
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly IGeneralService _generalService;
public GeneralController(IGeneralService generalService, IConfiguration configuration, IHttpContextAccessor httpContextAccessor)
{
_generalService = generalService;
_configuration = configuration;
_httpContextAccessor = httpContextAccessor;
}
[Authorize(Roles ="Admin")]
[Route("[action]")]
[HttpGet]
public async Task<DataTransfer<IEnumerable<MonthResponseModel>>> GetMonthList()
{
return await _generalService.GetMonthList();
}
React config file:
export const msalConfig = {
auth: {
clientId: "ddxxxx8-xxf-4xxd-bxx2-a4xxxxxd6c",
authority: "https://login.microsoftonline.com/061f82be-9xxe-4xx8-bdad-e1xxxxxb6d", // This is a URL (e.g. https://login.microsoftonline.com/{your tenant ID})
redirectUri: "http://localhost:3001",
},
cache: {
cacheLocation: "sessionStorage", // This configures where your cache will be stored
storeAuthStateInCookie: false, // Set this to "true" if you are having issues on IE11 or Edge
}
};
export const apiConfig = {
uri: "https://example.azurewebsites.net/api", // e.g. http://localhost:5000/api
scopes: ["api://3xxxx2-bxx4-4xxf-a72c-505xxxxx8b4/User.Read"] // e.g. ["scp1", "scp2"]
};
// Add scopes here for ID token to be used at Microsoft identity platform endpoints.
export const loginRequest = {
scopes: ["User.Read"]
};
// Add the endpoints here for Microsoft Graph API services you'd like to use.
export const graphConfig = {
graphMeEndpoint: "https://graph.microsoft.com/v1.0/me"
};
Here we have:
Client(React) App Essentials
Server(.net web API) App Essentials
I have exposed my API and added scope and authorized client Application:
Exposed API
I need help as I have been stuck in this issue from a couple of days and Kindly do let me know where to add Users in Client App or in Server app?
Issue Fixed!
In appsetting I changed "scopes": "api://3xxx52-bxx4-40xf-axxc-505xxxx8b4/User.Read" to "scopes": "User.Read"and reorder the middleware in Configure Method (Startup file):
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "Loreal TMS v1");
});
app.UseHttpsRedirection();
//app.UseStaticFiles();
app.UseCors(x => x
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
);
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}

CORS Error when React App tries to connect via SignalR to .NET CORE Web App having Windows Authentication enabled

I am trying to send data from React App to .NET Core Web App using SignalR.
The .NET Core Web App has Windows Authentication enabled. With Windows Authentication enabled, I am getting the CORS error when my React App tries to send message to .NET Core App via SignalR.
It works fine if I disable windows authentication and enable anonymous authentication.
Can you please help me with your valuable inputs to make the connection work?
React JS app code looks like below:
const hubConnection = new HubConnectionBuilder()
.withUrl(window.config.APP_URL, options)
.withAutomaticReconnect()
.build();
this.setState({ hubConnection }, () => {
this.state.hubConnection
.start()
.then(() => console.log("SignalR Connection started!"))
.catch((err) =>
console.log("SignalR Error while establishing connection :(", err)
);
});
}
sendMessage = () => {
console.log("sendMessage() Properties: ", this.props);
const signalRMessage = {
UserName: this.props.userName,
};
this.state.hubConnection
.invoke("SendMessage", signalRMessage)
.catch((err) => console.error(err));
};
I tried to explicitly add the ‘Access-Control-Allow-Origin’ header as shown below. But still I see the CORS error.
componentDidMount() {
let options = {
httpClient: {
post: (url, httpOptions) => {
// httpOptions.headers = {
// ...httpOptions.headers,
// "Access-Control-Allow-Origin": window.config.CORS_ALLOW_ORIGIN_URL,
// //"Access-Control-Allow-Methods": "POST, GET, HEAD",
// };
// httpOptions.method = "POST";
// httpOptions.url = url;
// return httpOptions;
const headers = {
...httpOptions.headers,
"Access-Control-Allow-Origin": window.config.CORS_ALLOW_ORIGIN_URL,
"Access-Control-Allow-Methods": "POST, GET, HEAD",
};
let newResponse = {};
return axios.post(url, {}, { headers }).then(response => {
return (newResponse = {
statusCode: response.status,
statusText: response.statusText,
content: JSON.stringify(response.data)
});
});
}
}
};
Below is the CORS error that I see in console logs at React App side:
enter image description here
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(IISDefaults.AuthenticationScheme);
services.AddRazorPages();
services.AddCors(options =>
{
options.AddPolicy("ClientPermissionPolicy", policy =>
{
policy.WithOrigins("https://xxxx.com")
.AllowAnyHeader()
.AllowAnyMethod().AllowCredentials();
});
});
...
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCors("ClientPermissionPolicy");
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
endpoints.MapHub<TapHub>("/hubs/tap");
});
}
Went through many posts here in stackoverflow and tried below but in vain.
In Configure():
app.UseCors(builder => builder.WithOrigins("https://xxxx.com").AllowAnyMethod().AllowAnyHeader().AllowCredentials());
In ConfigureServices():
services.AddCors(options =>
{
options.AddPolicy("ClientPermissionPolicy", policy =>
{
policy.WithOrigins("https://xxxxx.com")
.AllowAnyHeader()
.AllowAnyMethod().AllowCredentials()
.SetIsOriginAllowed((host) => true);
});
});
Tried AllowAnyOrigin()
Tried removing AllowCredentials()
Like I said above, it works fine if I disable windows authentication and enable anonymous authentication. The React App successfully connects to the hub endpoint in case of anonymous authentication. The CORS error comes into picture only when I enable windows authentication. I need Windows Authentication enabled for my requirement. Requesting you to help fix the issue.
Thanks!
A bit late, however I faced similar problem right now. Even with enabled CORS, it still rejected me. In the end, I found out that problem is in the
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
When I included CORS into this part, it started to work ... finally
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers().RequireCors("ClientPermissionPolicy");
});
You have to place UseCors between UseRouting and UseAutorization
app.UseRouting();
app.UseCors("ClientPermissionPolicy");
app.UseAuthorization();
and maybe you can try to move AddCors to the top of ConfigureServices method
Just the test pourposes I would use this
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(o => o.AddPolicy("ClientPermissionPolicy", builder =>
{
builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader();
}));
.....
}
only if it works, I would try to use specific origins.
For those using .NET Core 3.1, here is a COMPLETE solution (front-end to back-end):
My problem: When I enabled the windows authentication on my web API, I could not do fetch calls from my react app to my .NET Core 3.1 web API, CORS was freaking out. With Anonymous authentication it worked, but not when windows authentication is enabled.
1.launchSettings.json
this will be used only for your dev environnment, make sure windows auth is also enabled in IIS on your prod server.
{
"iisSettings": {
"windowsAuthentication": true,
"anonymousAuthentication": false,
"iisExpress": {
"applicationUrl": "http://localhost:58747",
"sslPort": 0
}
},
{... more settings if any}
}
2.Startup.cs:
CORS policy is enabled here. The order of methods is important here. Also, you don't need to set those in a web.config
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy("CorsPolicy", //give it the name you want
builder =>
{
builder.WithOrigins( "http://localhost:3000", //dev site
"production web site"
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials();
});
});
//database services here
services.AddControllers();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
// global policy same name as in the ConfigureServices()
app.UseCors("CorsPolicy");
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
3.Controller(s):
using Microsoft.AspNetCore.Cors;
... your other usings
namespace ProjectTest.Controllers
{
[ApiController]
[EnableCors("CorsPolicy")] //THIS HERE needs to be the same name as set in your startup.cs
[Route("[controller]")]
public class FooController:Controller
{
[HttpGet("getTest")]
public JsonResult GetTest()
{
return Json("bar");
}
}
}
4.React Component fetch call example:
The "credential: 'include'" is the secret
await fetch('http://localhost:3000/Foo/getTest', {
method: 'GET',
credentials: 'include'
}).then(resp => resp.json());
As mentioned here, the problem takes place because:
IIS's Windows Auth happens before ASP.NET Core runs, the ASP.NET Core
CORS implementation isn't able to process the OPTIONS request (because
the browser won't send your Windows credentials with it). The only
real solution here is to use the IIS CORS module since it runs before
Windows Authentication and can process the unauthenticated CORS
request.

.NET 5.0 + React + Google Auth

I am struggling to build a secure React web app with Net 5.0 backend (all in the same project) and would like some advice.
All within the same Visual Studio project.
Eg:
Project
ClientApp (React)
Controllers (C# endpoints eg /api/data, api/filtereddata)
Program.cs
Startup.cs
(Implementation #1)
I can make the front-end login using the 'react-google-login' npm package. That works well but it doesn't protect the endpoints in the controllers (/api/data).
<div>
<GoogleLogin
clientId={clientId}
buttonText="Login with Google"
onSuccess={onSuccess}
onFailure={onFailure}
cookiePolicy={'single_host_origin'}
style={{ marginTop: '100px' }}
isSignedIn={true}
/>
</div>
I have also discovered I can verify that google token on the server by using something akin to:
const onSuccess = (res) => {
const tokenBlob = { tokenId: res.tokenId };
axios.post(`/api/auth/google`, tokenBlob)
.then(res => {
})
.catch(function (error) {
console.log("axois error", error);
})
};
[Route("/api/[controller]")]
public class AuthController : Controller
{
[AllowAnonymous]
[HttpPost("google")]
public IActionResult Google([FromBody] GoogleToken t)
{
var payload = GoogleJsonWebSignature.ValidateAsync(t.tokenId, new GoogleJsonWebSignature.ValidationSettings()).Result;
}
}
But it seems awkward to do this for every API call that the UI makes.
(Implementation #2)
I have tried doing this all in the backend (Microsoft.AspNetCore.Authentication.Google), that sort of worked with AddGoogle & AddCookie, that would re-direct to a Google login page when I tried to get data from the backend (via [Authorize]) - but I could not get React to notice that it was logged in/out.
// ConfigureServices
services.AddCors(options =>
{
options.AddDefaultPolicy(builder => {
builder.WithOrigins("https://localhost","https://accounts.google.com")
.AllowAnyHeader().AllowAnyMethod();
});
});
services.AddControllers().AddNewtonsoftJson();
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(o =>
{
o.LoginPath = "/signin";
o.LogoutPath = "/signout"; // ??
o.ExpireTimeSpan = TimeSpan.FromHours(1);
})
.AddGoogle(options =>
{
options.ClientId = "";
options.ClientSecret = "";
options.SaveTokens = true;
options.CallbackPath = "/signin-google";
});
// Configure
app.UseCors();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseSpaStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints => {
endpoints.MapControllers();
});
app.UseSpa(spa => {
spa.Options.SourcePath = "ClientApp";
if (env.IsDevelopment()) {
spa.UseReactDevelopmentServer(npmScript: "start");
}
});
// Home controller
public class HomeController : Controller {
[Route("/signin")]
public IActionResult SignIn() {
var authProperties = new AuthenticationProperties { RedirectUri = "/"
};
return new ChallengeResult(GoogleDefaults.AuthenticationScheme, authProperties);
}
[Authorize]
[Route("/signout")]
[HttpPost]
public async Task<IActionResult> Logout()
{
await HttpContext.SignOutAsync();
return Ok("Logged out");
}
}
// Api controller
[Authorize]
[Route("api/[controller]")]
public class DataController : Controller
{
private readonly ILogger<DataController> _logger;
public MatchListController(ILogger<DataController> logger)
{
_logger = logger;
}
[HttpGet]
public ResponseViewModel Get([AllowNull] DateTime? d) => new ResponseViewModel(matchDate ?? DateTime.UtcNow)?.Result;
}
The second implementation will re-direct to Google and require the login but React doesn't know the page is logged in. So how can it get the logged info to display the username etc?
So what is the best practice? Am I close? I feel close!
What I'd love to see would be an example of the WeatherForecast React template in visual studio with a working Google login that uses [Authorize] on the API data controller.
Any suggestions welcome.
Edit: Added some code

Razor Pages Application not redirecting to IdentityServer4

I am having trouble getting my .NET Core site to redirect to my identity server for authentication when accessing a page. When I run the site locally this works fine. However, when I deploy the site it no longer works.
Here is the code for the application startup (just for the authentication)
public void ConfigureServices(IserviceCollection services) {
services
.AddAuthentication(options => {
options.DefaultScheme => "Cookies";
options.DefaultChallengeScheme = "oidc";
})
.AddCookie("Cookies")
.AddOpenIdConnect("oidc", options => {
options.Authority = "IdentityServerUrl";
options.ClientId = "clientId";
options.ResponseType = "code";
options.SaveTokens = true;
options.Scope.Add("scope");
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints => endpoints.MapRazorPages().RequireAuthorization());
}
And then in our page:
public class IndexModel : PageModel {
public async Task OnGetAsync() {
var authentication = await this.HttpContext.AuthenticateAsync();
var accessTokenJwt = authentication.Properties.Items[".Token.access_token"];
}
}
This is all working correctly when run locally. It is successfully redirecting to the identity server, logging in, returning to the application, and setting the cookies.
However, when this is deployed to a webserver it is not working at all. The await this.HttpContext.AuthenticateAsync(); is called and just immediately returns null. This results in an exception being thrown on the line below.
Any help with this would be much appreciated. Thanks in advance.

Azure Internal Server Error on ASP.NET Core Web API Controller

I've created a ASP.NET Core Web API Controller with React Js App and it on Azure. After sever try I am able to upload on Azure and now I'm getting error on my API. When I click on Customer it does not give me error but there is no data from SQL Database.
Can someone guide me on How to connect DB to my ASP.NET Core Web API or suggest me where am I doing wrong?
I tried post/add data to customer table but I am getting Internal server Error
Here is sql connection string in my appsetting.json
"ConnectionStrings": {
"DevConnection": "jdbc:sqlserver://aspapireact.database.windows.net:1433;database=ReactTask;user=*****;password=*****;encrypt=true;trustServerCertificate=false;hostNameInCertificate=*.database.windows.net;loginTimeout=30;"}
The Startup.cs
namespace RahulTask1
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddCors(options =>
{
options.AddDefaultPolicy(builder =>
{
builder.WithOrigins("https://aspapireact.azurewebsites.net")
.AllowAnyMethod()
.AllowAnyHeader();
});
});
// In production, the React files will be served from this directory
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp/build";
});
services.AddDbContext<DatabaseContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DevConnection")));
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseSpaStaticFiles();
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller}/{action=Index}/{id?}");
});
app.UseSpa(spa =>
{
spa.Options.SourcePath = "ClientApp";
if (env.IsDevelopment())
{
spa.UseReactDevelopmentServer(npmScript: "start");
}
});
}
}
}
And this the API I am trying to call
https://aspapireact.azurewebsites.net/api/Customers
You can see my code on GitHub
https://github.com/rlbrs/ASPAPIReact
In this project you will see the local server connection string but I've updated with above one and same with appserver.json
you can use the configuration builder to the configure services method. To build the key value pair from the appsettings.json on any environment based appsettings file, add following code to the ConfigureServices method (This is not mandatory)
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: false , reloadOnChange : true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);
And then you read the value for the connection string as
Configuration["ConnectionStrings:DevConnection"]
PS: Any particular reason you are using jdbc connection? why not use the standard dot net based connection string?

Resources