Search code examples
.netoauth-2.0identityserver4openid-connect

Securing a client in IdentityServer4


I have the following scenario:

enter image description here

I am confused as to how to set up API 2 in IdentityServer4, as it looks to me like it's both a Client (since it's consuming the resources provided by API 1) and an ApiResource (since I'm wanting to secure it so that only logged-in users can access it).

I have considered setting up API 2 as a Client and securing it with cookie authentication. I think this is similar to what they do in the MvcClient in their sample. However, I don't like it because all of the information about the user is stored server-side, so my JavaScript app has no way of knowing the user's name, email, etc.

What is the best way to handle this scenario?


Solution

  • Basically, you need to protect both of your API's with your Identity Server. Something like:

    API 1 Startup.cs:

    services.AddAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme) 
    .AddIdentityServerAuthentication(options => 
    { 
        options.Authority = "https://localhost:5000"; 
        options.SupportedTokens = SupportedTokens.Both; 
        options.RequireHttpsMetadata = false; 
        options.ApiName = "api1"; 
    });
    

    Same thing for API 2, but the options.ApiName should be different. Then, your javascript client, when being constructed on the Identity Server side, should be allowed to access these 2 api's (allowed scopes):

    new Client
        {
            ClientId = "your.js.client.id",
    
            AllowedGrantTypes = GrantTypes.Implicit,
            AllowAccessTokensViaBrowser = true,
    
            RedirectUris =           { "http://localhost:5003/callback.html" },
            PostLogoutRedirectUris = { "http://localhost:5003/index.html" },
            AllowedCorsOrigins =     { "http://localhost:5003" },
    
            AllowedScopes =
            {
                "api2",
                "api1"
            }
        }
    

    This code was from the official documentation.

    And then in API 2, when you want to call API 1's controller, you need something like:

    var client = new HttpClient();
    client.SetBearerToken(accessToken);
    client.GetStringAsync("https://localhost/api1/test");
    

    Where you get the access_token:

    [Authorize]
    public async Task<IActionResult> ControllerMethodInApi2()
    {
        var accessToken = await context.HttpContext.GetTokenAsync("access_token"); 
    
        return View();
    }
    

    This should work for you.