I could authenticate swagger on Azure AD B2C. It works fine on http://localhost:5078/ . But as soon as I push my website to azure I can not authenticate swagger. It still uses localhost:5078 as redirect URL and not azure website URL.
My code:
builder.Services.AddSwaggerGen(c => {
var OATH2 = "oauth2";
// Enabled OAuth security in Swagger. From here: https://stackoverflow.com/questions/66894523/swagger-not-able-to-authenticate-to-azure-ad-b2c
c.AddSecurityRequirement(new OpenApiSecurityRequirement() {
{
new OpenApiSecurityScheme {
Reference = new OpenApiReference {
Type = ReferenceType.SecurityScheme,
Id = OATH2
}
},
new List<string>()
}
});
c.AddSecurityDefinition(OATH2, new OpenApiSecurityScheme
{
Type = SecuritySchemeType.OAuth2,
Flows = new OpenApiOAuthFlows
{
Implicit = new OpenApiOAuthFlow()
{
AuthorizationUrl = new Uri($"{builder.Configuration["AzureAdB2C:Instance"]}/{builder.Configuration["AzureAdB2C:Domain"]}/{builder.Configuration["AzureAdB2C:SignUpSignInPolicyId"]}/oauth2/v2.0/authorize"),
TokenUrl = new Uri($"{builder.Configuration["AzureAdB2C:Instance"]}/{builder.Configuration["AzureAdB2C:Domain"]}/{builder.Configuration["AzureAdB2C:SignUpSignInPolicyId"]}/oauth2/v2.0/token"),
Scopes = new Dictionary<string, string>() { { builder.Configuration["AzureAdB2C:Scope"], "backend all" } }
}
}
});
});
....
app.UseSwagger();
app.UseSwaggerUI(c => {
c.OAuthClientId(builder.Configuration["AzureAdB2C:SwaggerClientId"]);
c.OAuthScopes(builder.Configuration["AzureAdB2C:Scope"]);
c.OAuthUsePkce();
});
OK on localhost:
Not OK on azure:
https://anna-carat-auth-test.azurewebsites.net/swagger/index.html
Both redirect URLs are registered in app:
How to set a proper redirect URL for swagger?
Created a sample Web Api application.
In Visual Studio click on connected services and add a dependency of Microsoft Identity platform as shown in below snippet.
Once the dependencies are added then in Program.cs file is updated with Azure AD related settings.
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"));
// It added the Authentication and Authorization methods.
app.UseAuthentication();
app.UseAuthorization();
In Program.cs file made the code changes as shown below.
builder.Services.AddSwaggerGen(
x =>
{
x.SwaggerDoc("v1", new Microsoft.OpenApi.Models.OpenApiInfo
{
Title = "Swagger Azure AD Demo",
Version = "v1"
});
x.AddSecurityDefinition("oauth2", new Microsoft.OpenApi.Models.OpenApiSecurityScheme
{
Description = "Oauth2.0 which uses AuthorizationCode flow",
Name = "oauth2.0",
Type = SecuritySchemeType.OAuth2,
Flows = new OpenApiOAuthFlows
{
AuthorizationCode = new OpenApiOAuthFlow
{
AuthorizationUrl = new Uri(builder.Configuration["SwaggerAzureAD:AuthorizationUrl"]),
TokenUrl = new Uri(builder.Configuration["SwaggerAzureAD:TokenUrl"]),
Scopes = new Dictionary<string, string>
{
{builder.Configuration["SwaggerAzureAD:Scope"], "Access API as User" }
}
}
}
});
x.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference= new OpenApiReference{Type=ReferenceType.SecurityScheme,Id="oauth2"}
},
new[]{builder.Configuration["SwaggerAzureAD:Scope"]}
}
});
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI(x=>
{
x.OAuthClientId(builder.Configuration["SwaggerAzureAD:ClientId"]);
x.OAuthUsePkce();
});
}
And the AppSettings.Json
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"Domain": "Something.onmicrosoft.com",
"TenantId": "TenantID",
"ClientId": "ClientID",
"CallbackPath": "/signin-oidc",
"Scopes": "access_as_user"
},
// These values need to be copied from App registartion
"SwaggerAzureAD": {
"AuthorizationUrl": "",
"TokenUrl": "",
"ClientId": "",
"Scope": ""
}
}
Expose API from App registration.
API Permissions need to be given in the App registrations of Azure.
And has to be copied the value and need to use in the scope attribute of AppSettings.json
And redirection urls to be mentioned and to be used in AppSettings.json form App registration -> Authentication as shown in below snippet.
And able to get the response without any issues.
Response:
Related
I am trying to implement AuthorizationCode grant type for SwaggerUI that will work with Azure AD.
The error that I am getting is:
Content Security Policy: The page’s settings blocked the loading of a
resource at
https://login.microsoftonline.com/{tenant-id}/oauth2/v2.0/token
(“connect-src”)
I used web debugging proxy tool to check all network requests and I see there is a request to my redirect uri with state and authorization code that should be used for token exchange, but that doesn't happen.
My SwaggerUI setup:
// Enable middleware to serve generated Swagger as a JSON endpoint.
app.UseSwagger();
// Enable middleware to serve swagger-ui (HTML, JS, CSS etc.), specifying the Swagger JSON endpoint.
app.UseSwaggerUI(c =>
{
c.OAuthClientId(Configuration["Swagger:ClientId"]);
c.OAuthAppName("My API");
c.OAuthUsePkce();
c.OAuthScopeSeparator(" ");
c.InjectStylesheet("/swagger-ui/dark.css");
c.DisplayRequestDuration();
});
...
string authUrl = $"https://login.microsoftonline.com/{Configuration["AzureAD:TenantId"]}/oauth2/v2.0/authorize";
c.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
{
Description = "OAuth2.0 Auth Code with PKCE",
Name = "oauth2",
Type = SecuritySchemeType.OAuth2,
In = ParameterLocation.Header,
Flows = new OpenApiOAuthFlows
{
AuthorizationCode = new OpenApiOAuthFlow
{
AuthorizationUrl = new Uri(authUrl, UriKind.Absolute),
TokenUrl = new Uri(authUrl.Replace("authorize", "token"), UriKind.Absolute),
Scopes = new Dictionary<string, string>
{
{ $"api://{Configuration["AzureAD:ResourceId"]}/user_impersonation", "user impersonation" }
}
}
}
});
c.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "oauth2" }
},
Array.Empty<string>()
}
});
I’m trying to use Microsoft.Identity.Web to call an API from my .NET 6 Blazor server app. I can successfully login to authorized pages in my Blazor app but when I try to make an API call using CallWebApiForUserAsync I get an inner exception of “No account or login hint was passed to the AcquireTokenSilent call”.
The couple of posts here on Stack Overflow and the MS documentation look to me like I have it configured correctly. What am I missing?
appsettings.json:
"AzureAd": {
"Authority": "https://hivercom.b2clogin.com/XXXXXX.onmicrosoft.com/B2C_1_SignUpSignIn",
"Instance": "https://XXXXXX.b2clogin.com",
"TenantId": "XXXXXX-XXXXXX-XXXXXX-XXXXXX-XXXXXX",
"ClientId": "XXXXXX-XXXXXX-XXXXXX-XXXXXX-XXXXXX",
"CallbackPath": "/signin-oidc",
"Domain": "XXXXXX.onmicrosoft.com",
"SignedOutCallbackPath": "/signout/B2C_1_susi",
"SignUpSignInPolicyId": "B2C_1_SignUpSignIn",
"ResetPasswordPolicyId": "B2C_1_PasswordReset",
"EditProfilePolicyId": "B2C_1_EditProfile",
"ClientSecret": "XXXXXXXXXXXXXXXXXX"
},
"HiverAPI": {
"BaseUrl": "https://localhost:7075",
"Scopes": "https://XXXXXX.onmicrosoft.com/XXXXXX-XXXXXX-XXXXXX-XXXXXX-XXXXXX/all"
},
Program.cs
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.Identity.Web;
using Microsoft.Identity.Web.UI;
using BlazorB2C.Data;
using Microsoft.Identity.Web.TokenCacheProviders.InMemory;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.Authorization;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpClient();
builder.Services.AddMicrosoftIdentityWebAppAuthentication(builder.Configuration, "AzureAd")
.EnableTokenAcquisitionToCallDownstreamApi(new string[] { "https://XXXXXX.onmicrosoft.com/XXXXXX-XXXXXX-XXXXXX-XXXXXX-XXXXXX/all" })
.AddDownstreamWebApi("HiverService", builder.Configuration.GetSection("HiverAPI"))
.AddInMemoryTokenCaches();
builder.Services.AddAuthorization(options =>
{
options.FallbackPolicy = options.DefaultPolicy;
});
builder.Services.AddRazorPages().AddMvcOptions(options =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
}).AddMicrosoftIdentityUI();
builder.Services.AddServerSideBlazor()
.AddMicrosoftIdentityConsentHandler();
builder.Services.Configure<OpenIdConnectOptions>(OpenIdConnectDefaults.AuthenticationScheme, options =>
{
options.Events.OnSignedOutCallbackRedirect = context =>
{
context.HttpContext.Response.Redirect(context.Options.SignedOutRedirectUri);
context.HandleResponse();
return Task.CompletedTask;
};
});
builder.Services.AddSingleton<WeatherForecastService>();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.MapBlazorHub();
app.MapFallbackToPage("/_Host");
app.Run();
Level.razor:
#page "/level"
#using Microsoft.Identity.Web
#inject IHttpClientFactory HttpClientFactory
#inject Microsoft.Identity.Web.ITokenAcquisition TokenAcquisitionService
#inject Microsoft.Identity.Web.IDownstreamWebApi DownstreamWebApi
#inject MicrosoftIdentityConsentAndConditionalAccessHandler ConsentHandler
#attribute [Authorize]
#attribute [AuthorizeForScopes(ScopeKeySection = "HiverAPI:Scopes")]
<PageTitle>Level</PageTitle>
Log out
<h3>Level</h3>
#code {
private const string ServiceName = "HiverService";
protected override async Task OnInitializedAsync()
{
try
{
error >> string token = await TokenAcquisitionService.GetAccessTokenForUserAsync(new string[] { "https://XXXXXX.onmicrosoft.com/XXXXXX-XXXXXX-XXXXXX-XXXXXX-XXXXXX/all" });
error >> var value = await DownstreamWebApi.CallWebApiForUserAsync(
ServiceName,
options =>
{
options.RelativePath = $"HiverUser";
});
}
catch (Exception ex)
{
var message = ex.Message;
ConsentHandler.HandleException(ex);
}
try
{
error >> await DownstreamWebApi.CallWebApiForUserAsync(
ServiceName,
options =>
{
options.HttpMethod = HttpMethod.Put;
options.RelativePath = $"HiverUser/0fd30e94-a116-4ef0-b222-4125546b8561";
});
}
catch (Exception ex)
{
var message = ex.Message;
ConsentHandler.HandleException(ex);
}
}
}
Azure configuration for client app:
Azure configuration for API
CallWebApiForAppAsync uses the on-behalf flow, which is not available for Azure AD B2C.
https://github.com/AzureAD/microsoft-identity-web/wiki/b2c-limitations
You cannot use ITokenAcquisition.GetTokenForAppAsync or IDownstreamApi.CallWebApiForAppAsync in Azure AD B2C web apps.
https://learn.microsoft.com/en-us/azure/active-directory-b2c/access-tokens
As an alternative, you can request access tokens for downstream APIs(Hiver.API in your case) using GetAccessTokenForUserAsync. The resulting access token can be used to call the API. You'll need to use a standard HttpClient instead of IDownstreamWebApi. Full example can be found here:
https://github.com/Azure-Samples/ms-identity-blazor-server/blob/main/WebApp-your-API/B2C/README-Incremental.md
Relevant code from Github:
private async Task PrepareAuthenticatedClient()
{
var accessToken = await _tokenAcquisition.GetAccessTokenForUserAsync(new[] { _TodoListScope });
Debug.WriteLine($"access token-{accessToken}");
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
_httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
}
I need help, I got stuck for a few days trying to protect a Web API (ASP.NET Core 6) by sending access token from users (Azure Ad B2C with google provider/local account) signed in with authentication code flow (PKCE).
This generates a (401) unauthorized error. What is going wrong?
The Next.js Application: (helloworld.webapp)
Azure Ad B2C settings
Manage -> Authentication
Single-page-application with redirect uri: http://localhost:3000
Manage -> API permissions
helloworld.api
access_as_user | admin consent required: yes | status: ✅ Granted for helloworld
Microsoft Graph
offline_access | admin consent required: yes | status: ✅ Granted for helloworld
openid | admin consent required: yes | status: ✅ Granted for helloworld
(unchecked)
🔲 Access tokens (used for implicit flows)
🔲 ID tokens (used for implicit and hybrid flows)
This is how you log in.
const login = (event: React.MouseEvent<HTMLButtonElement>) => {
console.log("only logs in browser console")
instance.loginRedirect({
scopes: [
"openid",
"offline_access",
// ✅ checked for typo
"https://helloworld.onmicrosoft.com/8a1bc000-2000-4000-a000-d3156a663000/access_as_user",
]
})
}
In the following snippet you can see how I get my accessToken.
const postData = (event: React.MouseEvent<HTMLButtonElement>) => {
event.preventDefault();
// to prevent ssr mismatch errors.
if (!data && inProgress === InteractionStatus.None) {
instance
.acquireTokenSilent({
scopes: [
"openid",
"offline_access",
// ✅ checked for typo
"https://helloworld.onmicrosoft.com/8a1bc000-2000-4000-a000-d3156a663000/access_as_user",
]
})
.then((accessTokenResponse) => {
let accesstoken = accessTokenResponse.accessToken;
console.log(accesstoken); // 👍only logs in browser console.
// // ✅ weatherforecast endpoint checked. Maps to http://localhost:5015/api/:path*
fetch("/api/net/weatherforecast", {
method: "GET",
headers: {
Authorization: `Bearer ${JSON.stringify(accesstoken)}`,
},
})
.then((res) => console.log(res))
.catch((err) => console.log(err));
});
}
};
I have the following rule in next.config.js
async rewrites() {
return {
fallback: [
{
source: "/api/net/:path*",
destination: "http://localhost:5015/api/:path*",
},
],
};
},
ASP.NET Core 6 application: (helloworld.api)
manage -> expose API
scopes ✅ all checked for typo
https://helloworld.onmicrosoft.com/8a1bc000-2000-4000-a000-d3156a663000/access_as_user
Who can consent: Admins only
State: Enabled
The appsettings.json
"AzureAdB2C": {
"Instance": "https://helloworld.b2clogin.com/",
"ClientId": "8a1bc000-2000-4000-a000-d3156a663000",
"Domain": "helloworld.onmicrosoft.com",
"Scopes": "access_as_user",
"SignUpSignInPolicyId": "B2C_1_authflow"
},
The Program.cs generated with dotnet new webapi -au IndividualB2C with added cors.
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Identity.Web;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAdB2C"));
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddCors(o => o.AddPolicy("default", builder =>
{
builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader();
}));
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI();
}
else
{
app.UseHttpsRedirection();
}
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
The WeatherForecastController
[Authorize]
[ApiController]
[Route("api/[controller]")]
[RequiredScope(RequiredScopesConfigurationKey = "AzureAd:Scopes")]
public class WeatherForecastController : ControllerBase
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
private readonly ILogger<WeatherForecastController> _logger;
public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}
[HttpGet(Name = "GetWeatherForecast")]
public IEnumerable<WeatherForecast> Get()
{
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.ToArray();
}
}
And lastly, the user flow
User Flow (B2C_1_authflow)
Possible causes?:
no https as this gave a net::ERR_CERT_AUTHORITY_INVALID
else
{
app.UseHttpsRedirection();
}
Some problem because next.js is a full-stack application? I believe it acts as SPA as I delay the acquiring accessToken untill InteractionStatus.None?
Please check if you need to modify the way of provisioning scope in app settings. Try giving complete scope https://<tenant>/api/<scope>.
{
"AzureAdB2C": {
"Instance": "https://<your-tenant-name>.b2clogin.com",
"ClientId": "<web-app-application-id>",
"Domain": "<your-b2c-domain>",
"SignUpSignInPolicyId": "<your-sign-up-in-policy>"
// "SignedOutCallbackPath": "/signout/<your-sign-up-in-policy>",
},
"TodoList": {
"TodoListScope": "https://contoso.onmicrosoft.com/api/access_as_user openid offline_access",
"TodoListBaseAddress": "https://localhost:44332"
}
}
Also check if app.UseHttpsRedirection(); is to be used after if loop
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
Also please make sure to recheck and give proper redirect url , which has to be same in portal and authorization request. It has to be valid url
Reference:
Configure authentication in a sample web application that calls a web API by using Azure Active Directory B2C | Microsoft Docs
I have following situation:
I'm trying to integrate ADB2C with my SPA app in backend:
IdentityModelEventSource.ShowPII = true;
services.AddSession();
services.AddAuthentication(AzureADB2CDefaults.AuthenticationScheme)
.AddAzureADB2C(options => configuration.Bind("AzureAd", options))
.AddApiKeySupport(options => { });
services.AddOptions<OpenIdConnectOptions>(AzureADB2CDefaults.OpenIdScheme).Configure<IGraphServiceClient, ILogRepository>((options, graphClient, logRepo) =>
{
var oldPostValidate = options.Events.OnTokenValidated;
options.Events.OnTokenValidated = async (context) =>
{
await new AzureADB2CHelper(graphClient).OnTokenValidated(context);
await oldPostValidate(context);
};
});
Also I set configuration:
"AzureAd": {
"Instance": "https://rqrar.b2clogin.com/",
"Domain": "rqrar.onmicrosoft.com",
"TenantId": "guid",
"ClientId": "guid",
"CallbackPath": "/api/response-oidc",
"SignUpSignInPolicyId": "B2C_1_SIGN_IN",
"ResetPasswordPolicyId": "B2C_1_PASSWORD_RESET",
}
In app registration I have application with redirect uri: https://custom-domain.com/api/response-oidc
And now if user will correctly login I'm expecting he will be redirected to https://custom-domain.com/api/response-oidc instead of this ADB2C is trying redirect user to https://default-generated-url-by-azure.azurewebsites.net/api/response-oidc
Have anyone idea what can I missing ?
I want to host my REST API on Azure Service App with authorization bearer token.
On Azure portal I've done:
Create new App Service (testservice).
On Authentication/Authorization:
App Service Authentication -> On
Action to take when request is not authenticated -> Log in with Azure Active Directory. Set Authentication Providers to Active Directory Authentication with Management mode: Express and create new Azure AD Application (register new app: testserviceapp)
Token Store -> On
On App registrations -> testserviceapp:
Authentication -> Web -> Redirect URIs: https://testservice.azurewebsites.net/.auth/login/aad/callback
Authentication -> Web -> Implicit grant -> Access tokens: true, ID tokens: true
Authentication -> Supported account types -> Accounts in this organizational directory only (... - Single tenant)
Authentication -> Advanced settings -> Treat application as a public client: No
Certificates & secrets -> create new ClientSecret
Expose an API -> Add a scope: https://testservice.azurewebsites.net/user_impersonation
Expose an API -> Add a scope: https://testservice.azurewebsites.net/WeatherForecast
Next, I created RestApiService project in VisualStudio and publish into Azure.
appsettings.json in my RestApiService host:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"AzureAd": {
"ClientId": "xxx",
"Domain": "xxx.onmicrosoft.com",
"Instance": "https://login.microsoftonline.com/",
"TenantId": "xxx",
"CallbackPath": "/signin-oidc",
"ClientSecret": "xxx",
"AppIDURL": "https://testservice.azurewebsites.net",
"ConfigView": "API"
}
}
WeatherForecastController.cs:
[ApiController]
[Route("[controller]")]
[Authorize]
public class WeatherForecastController : ControllerBase
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
private readonly ILogger<WeatherForecastController> _logger;
public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}
[HttpGet]
public IEnumerable<WeatherForecast> Get()
{
var rng = new Random();
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
})
.ToArray();
}
}
Startup.cs:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(AzureADB2CDefaults.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.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
On client app I successfully get AccessToken:
static AuthToken GetToken()
{
var uri = "https://login.microsoftonline.com/";
var method = $"{TenantID}/oauth2/token";
var client = new RestClient(uri);
var request = new RestRequest($"{uri}{method}", Method.POST);
request.AddParameter("grant_type", "client_credentials");
request.AddParameter("client_id", ClientID);
request.AddParameter("client_secret", ClientSecret);
request.AddParameter("resource", "https://testservice.azurewebsites.net/");
return client.Execute<AuthToken>(request).Data;
}
But when I try to call api with this token, I receive 401 Unauthorized error (You do not have permission to view this directory or page.):
static void GetItems(string token)
{
var client = new RestClient("https://testservice.azurewebsites.net/");
var request = new RestRequest("https://testservice.azurewebsites.net/WeatherForecast", Method.GET);
request.AddHeader("Authorization", $"bearer {token}");
var response = client.Execute(request);
}
What am I doing wrong?