0
votes

Good morning, I need to have in same project both web api and web app mvc. Web api has to be protected via bearer token and web app mvc has to be authenticated via identity server. Is it possible protecting a scope and a client in same project?

I think I have to do something like this in startup

//this to protect scope api1
services.AddAuthentication("Bearer")
    .AddJwtBearer("Bearer", options =>
    {
        options.Authority = "http://localhost:5000/";
        options.RequireHttpsMetadata = false;

        options.Audience = "api1";
    });

//this to authenticate mvc client
services.AddAuthentication(options =>
{
    options.DefaultScheme = "Cookies";
    options.DefaultChallengeScheme = "oidc";
})
.AddCookie("Cookies", options =>
{
    options.AccessDeniedPath = "/account/denied";
})
.AddOpenIdConnect("oidc", options =>
{                
    options.SignInScheme = "Cookies";

    options.Authority = "http://localhost:5000",
    options.RequireHttpsMetadata = false;

    options.ResponseType = "id_token token";
    options.ClientId = "mvc-implicit";
    options.SaveTokens = true;

    options.Scope.Clear();
    options.Scope.Add("openid");
    options.Scope.Add("profile");
    options.Scope.Add("api1");    
    options.GetClaimsFromUserInfoEndpoint = true;    
    options.ClaimActions.MapJsonKey("role", "role", "role");
    options.TokenValidationParameters = new TokenValidationParameters
    {
        NameClaimType = "name",
        RoleClaimType = "role"
    };                
});

Now, I have to call my Api1 using client_credential with an external client. But it returns me at login page.

Is it possible to do what I want? Protected WebApi and Authenticated MVC client in same project?

1

1 Answers

0
votes

Now, I have to call my Api1 using client_credential with an external client. But it returns me at login page.

That seems you misunderstand the scenario . Your MVC application is client also is a resource application which protected by Identity Server (in Config.cs):

public static IEnumerable<ApiResource> GetApis()
{
    return new List<ApiResource>
    {
        new ApiResource("api1", "My API")
    };
 }

I assume you have api controller in your MVC application :

[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
    // GET: api/Values
    [HttpGet]
    [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
    public IEnumerable<string> Get()
    {
        return new string[] { "value1", "value2" };
    }
}

And you have config to protect the api actions by using AddJwtBearer :

services.AddAuthentication("Bearer")
.AddJwtBearer("Bearer", options =>
{
    options.Authority = "http://localhost:5000/";
    options.RequireHttpsMetadata = false;

    options.Audience = "api1";
});

That means any request to access the Get action should have an authentication bearer header with access token append , the access token is issued by your Identity Server(endpoint is http://localhost:5000/) and the audience is api1 .

Now your another client could use client credential flow to acquire access token to access your web application :

var client = new HttpClient();

var disco = await client.GetDiscoveryDocumentAsync("http://localhost:5000");
if (disco.IsError)
{
    Console.WriteLine(disco.Error);
    return;
}

// request token
var tokenResponse = await client.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest
{
    Address = disco.TokenEndpoint,
    ClientId = "client",
    ClientSecret = "secret",

    Scope = "api1"
});

And call your protected actions :

var apiClient = new HttpClient();
apiClient.SetBearerToken(tokenResponse.AccessToken);

var response = await apiClient.GetAsync("http://localhost:64146/api/values");
if (!response.IsSuccessStatusCode)
{
    Console.WriteLine(response.StatusCode);
}
else
{
    var content = await response.Content.ReadAsStringAsync();
    Console.WriteLine(JArray.Parse(content));
}

So it won't redirect to login page , since client credential in fact is sending HTTP POST request to get access token with app's credential . There is no login page in this scenario .