I am trying to get access token from Identity Server 4 in my .Net 6 solution. I have 3 projects are running : Identity Server to get access token from it Movies.API to access secured resource Movies.Client to calling the api and get the secured resource using the access token that I got it from Identity Server using http message handler
here are my code for identity server config (related Clients):
public class Config
{
public static IEnumerable<Client> Clients =>
new Client[]
{
new Client
{
ClientId = "movieClient",
AllowedGrantTypes = GrantTypes.ClientCredentials,
ClientSecrets =
{
new Secret("secret".Sha256())
},
AllowedScopes = { "movieAPI" } // as the name in ApiScopes static list
},
new Client
{
ClientId = "movies_mvc_client",
ClientName = "Movies MVC Web App",
AllowedGrantTypes = GrantTypes.Code,
RequirePkce = false,
AllowRememberConsent = false,
RedirectUris = new List<string>()
{
"https://localhost:5002/signin-oidc"
},
PostLogoutRedirectUris = new List<string>()
{
"https://localhost:5002/signout-callback-oidc"
},
ClientSecrets = new List<Secret>
{
new Secret("secret".Sha256())
},
AllowedScopes = new List<string>
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
}
}
};
public static IEnumerable<ApiScope> ApiScopes =>
new ApiScope[]
{
new ApiScope("movieAPI","Movie API")
};
// rest of the code ...
and here are the injected IHttpClientFactory in the service GetMovies() :
public async Task<IEnumerable<Movie>> GetMovies()
{
// ** OPTION 1 **
var httpClient = _httpClientFactory.CreateClient("MovieAPIClient");
var request = new HttpRequestMessage(HttpMethod.Get, "/api/movies/");
// using the handler
var response = await httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false);
response.EnsureSuccessStatusCode();
var content = await response.Content.ReadAsStringAsync();
var movieList = JsonConvert.DeserializeObject<List<Movie>>(content);
return movieList;
...
and here are the implementation of the request handler :
and finally here are the registration of the HttpClient in Movie.Client Program.cs :
// 1- create an httpclient used for accessing in Movies.API
builder.Services.AddTransient<AuthenticationDelegatingHandler>();
builder.Services.AddHttpClient("MovieAPIClient", client =>
{
client.BaseAddress = new Uri("https://localhost:5001/");
client.DefaultRequestHeaders.Clear();
client.DefaultRequestHeaders.Add(HeaderNames.Accept, "application/json");
}).AddHttpMessageHandler<AuthenticationDelegatingHandler>();
// 2- create an httpclient used for accessing in the IDP
builder.Services.AddHttpClient("IDPClient", client =>
{
client.BaseAddress = new Uri("https://localhost:5005/");
client.DefaultRequestHeaders.Clear();
client.DefaultRequestHeaders.Add(HeaderNames.Accept, "application/json");
}).AddHttpMessageHandler<AuthenticationDelegatingHandler>();
builder.Services.AddSingleton(new ClientCredentialsTokenRequest
{
Address = "https://localhost:5005/connect/token",
ClientId = "movieClient",
ClientSecret = "secret",
Scope = "movieAPI"
});
now in the debugging : every time I hit continue button I get back again to SendAsync() in the handler.
Could anyone give me a hand to fix this issue, Thank you.
I find the problem !, it is because I am using the handler on "IDPClient" which it should be handled by Identity Server 4 side.
before
// 2- create an httpclient used for accessing in the IDP
builder.Services.AddHttpClient("IDPClient", client =>
{
client.BaseAddress = new Uri("https://localhost:5005/");
client.DefaultRequestHeaders.Clear();
client.DefaultRequestHeaders.Add(HeaderNames.Accept, "application/json");
}).AddHttpMessageHandler<AuthenticationDelegatingHandler>(); // remove the handler
after
// 2- create an httpclient used for accessing in the IDP
builder.Services.AddHttpClient("IDPClient", client =>
{
client.BaseAddress = new Uri("https://localhost:5005/");
client.DefaultRequestHeaders.Clear();
client.DefaultRequestHeaders.Add(HeaderNames.Accept, "application/json");
});
and it will works!