Hello there,
I’m trying very hard to implement Auth0 in my Angular 9.1.14 application, but I can’t still figure out what the problem.
I’ve been able to add login the my my app, but I fail to implement call to my C# .Net Core 5 REST API.
I’ve flowed the tutorial many time, but still all call I made to my API end with * HTTP Error. 401*
Here more details:
Angular App config:
AppModule:
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { RouterModule } from '@angular/router';
import { AppComponent } from './app.component';
import { NavMenuComponent } from './nav-menu/nav-menu.component';
import { HomeComponent } from './home/home.component';
import { DevicesComponent } from './Device/devices.component';
import { DeviceComponent } from './Device/device.component';
import { SelectListComponent } from './components/selectlist.component/select.list.component'; import { GeneralNoteComponent } from './components/generalNote.compoment/generalNote.compoment'; import { DeviceMaintenanceComponent } from "./components/devicemaintenance.component/devicemaintenance.component"; import { DeviceLoanComponent } from './components/deviceloan.component/deviceloan.component';
import { AuthModule } from '@auth0/auth0-angular'; import { LoggedUserComponent } from './components/loggedUser.Component/loggedUser.Component';
import { LoginComponent } from './components/login.component/login.component';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { AuthHttpInterceptor, AuthGuard } from '@auth0/auth0-angular';
@NgModule({
declarations: [
AppComponent,
NavMenuComponent,
HomeComponent,
DevicesComponent,
DeviceComponent,
SelectListComponent,
DeviceMaintenanceComponent,
DeviceLoanComponent,
GeneralNoteComponent,
LoggedUserComponent,
LoginComponent
],
imports: [
BrowserModule.withServerTransition({ appId: 'ng-cli-universal' }),
HttpClientModule,
FormsModule,
RouterModule.forRoot([
{ path: '', component: DevicesComponent, canActivate: [AuthGuard] },
{ path: 'login', component: LoginComponent },
{ path: 'device', component: DeviceComponent, canActivate: [AuthGuard] },
{ path: 'generalNote', component: GeneralNoteComponent, canActivate: [AuthGuard] }
]),
AuthModule.forRoot({
domain: 'dev-***.us.auth0.com',
clientId: 'Sk*********dm',
audience: 'https://dev-***.us.auth0.com/api/v2/',
httpInterceptor: {
allowedList: [
{
// Match any request that starts 'https://dev-sss.us.auth0.com/api/v2/' (note the asterisk)
uri: 'https://dev-***.us.auth0.com/api/v2/*',
tokenOptions: {
// The attached token should target this audience
audience: "https://dev-***.us.auth0.com/api/v2/",
// The attached token should have these scopes
scope: 'device:read'
}
}
]
}
})
],
providers: [AuthGuard,
{ provide: HTTP_INTERCEPTORS, useClass: AuthHttpInterceptor, multi: true }
],
bootstrap: [AppComponent]
})
export class AppModule { }
API Call:
const options = { params: new HttpParams() };
this.http.get<device[]>(this.apiUrl + "device/getall", options)
.subscribe(
result => this.devices = result,
error => console.error(error)
);
.Net Core 5 API
namespace Equipment.Api
{
using System;
using System.Threading.Tasks;
using Common.Interfaces;
using Laumie.Infrastructure.Web.Authorization;
using Laumie.Infrastructure.Web.Middleware;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.OpenApi.Models;
using Presentation;
using Presentation.Interface;
using Services;
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.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "Equipment.Api", Version = "v1" });
});
services.AddMvc(x => x.EnableEndpointRouting = false);
services.AddCors(options =>
{
options.AddPolicy("AllowSpecificOrigin",
builder =>
{
builder
.WithOrigins("http://localhost:4200")
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials();
});
});
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.Authority = "dev-***.us.auth0.com";
options.Audience = "apikey://666fcd34*****";
options.RequireHttpsMetadata = false;
options.Events = new JwtBearerEvents
{
OnAuthenticationFailed = context =>
{
throw new Exception($"Authentication failed for MetadataAddress {context.Options.MetadataAddress} with exception: {context.Exception}");
var logger = context.HttpContext.RequestServices.GetRequiredService<ILoggerFactory>().CreateLogger(nameof(JwtBearerEvents));
logger.LogWarning($"Authentication failed for MetadataAddress {context.Options.MetadataAddress} with exception: {context.Exception}");
return Task.CompletedTask;
}
};
});
services.AddAuthorization(options =>
{
options.AddPolicy("device:read", policy => policy.Requirements.Add(new HasScopeRequirement("device:read", "dev-***.us.auth0.com")));
});
services.RegisterDataServices();
services.AddSingleton<IAuthorizationHandler, HasScopeHandler>();
services.AddTransient<SelectListService>();
services.AddTransient<IHttpContextAccessor, HttpContextAccessor>();
services.AddScoped<HostNameProviderService>();
services.AddTransient<IGeneralNoteService, GeneralNoteService>();
services.AddTransient<IDeviceService, DeviceService>();
services.AddTransient<ICountryService, CountryService>();
services.AddTransient<IDeviceService, DeviceService>();
services.AddTransient<IDeviceLoanService, DeviceLoanService>();
services.AddTransient<DeviceMaintenanceService>();
services.AddTransient<ICountryPresentationService, CountryPresentationService>();
services.AddTransient<IDevicePresentationService, DevicePresentationService>();
}
// 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.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "Equipment.Api v1"));
}
app.UseMiddleware<ErrorLoggerMiddleware>();
app.UseMiddleware<TimedHttpCallMiddleware>();
app.UseCors("AllowSpecificOrigin");
app.UseAuthentication();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
}
API Controller:
namespace Equipment.Api.Controllers
{
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Common.DtoModel;
using Common.Interfaces;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
[ApiController]
[Route("[controller]")]
public class DeviceController : ControllerBase
{
private readonly IDeviceService _deviceService;
public DeviceController(IDeviceService deviceService)
{
_deviceService = deviceService;
}
[Authorize]
[HttpGet("GetAll")]
public async Task<IEnumerable<Device>> GetAll()
{
return await _deviceService.GetAllAsync();
}
[HttpGet]
public async Task<Device> Get(Guid id)
{
return await _deviceService.GetByIdAsync(id);
}
[HttpPost]
public async Task Post([FromBody] Device device)
{
await _deviceService.UpdateAsync(device);
}
[HttpPut]
public async Task Put([FromBody] Device device)
{
await _deviceService.Insert(device);
}
}
}
The error that I get from Chrome Debugger:
{
"headers": {
"normalizedNames": {},
"lazyUpdate": null,
"headers": {}
},
"status": 401,
"statusText": "OK",
"url": "https://localhost:44335/device/getall",
"ok": false,
"name": "HttpErrorResponse",
"message": "Http failure response for https://localhost:44335/device/getall: 401 OK",
"error": null
}
Auth0 Application API Config
- Identifier : “apikey://666fcd34*****”"
- Enable RBAC : On
- Permission: device:read
Auth0 Application Config
Domain: dev-*** .us.auth0.com
Client Id: Sk*********dm
Application Type : SPA
Token Endpoint: None
Grant Type: implicit, AuthorizationCode, RefreshToken
API URL: http://localhost:62816 / https://localhost:44335
Environement
- Visual Studio 2019 (last update - 16.9.3)
- Windows 10 (last update - 20H2)
- Angular 9.1.14
- .Net Core Framework 5.0