Search code examples
identityserver4flurl

Flurl calling IdentityServer4


I'm attempting to call Identity Server 4 with Flurl

Im getting a 400 back from the ID server. The credentials etc work when I make the call with PostMan or with the methods available in IdentityModel.Client.

I am unsure about the Post i.e. PostUrlEncodedAsync As you can see I have tried various combinations.

This.. does not work

var address = "http://localhost:8027/connect/token";
var x = await address
.WithBasicAuth("clientName", "secretValue")
.SetQueryParams(
    new
    {
        GrantType = "client_credentials",
        Scope = "requiredScope"
    }
)
.PostUrlEncodedAsync(new { });
//.SendAsync(HttpMethod.Post, null, CancellationToken.None);
//.SendAsync(HttpMethod.Post, y);

This.. does.

var apiClientCredentials = new ClientCredentialsTokenRequest()
{
    Address = "http://localhost:8027/connect/token",

    ClientId = "clientName",
    ClientSecret = "secretValue",
    Scope = "requiredScope"
};

var client = new HttpClient();

var tokenResponse = await client.RequestClientCredentialsTokenAsync(apiClientCredentials);
if (tokenResponse.IsError)
{
}

I can see that deep doen inside 'RequestClientCredentialsTokenAsync' it does parameters.Add to add grant type and scope hence I have added those as params.

Have also tried adding the client id and secret to the query params.

Same 400 message.

Any help greatly appreciated.


Solution

  • I believe the difference is that IdentityModel knows to serialize those ClientCredentialsTokenRequest property names like ClientId and GrantType to snake-case, i.e. client_id and grant_type, as required by OAuth2. When you hand Flurl an anonymous object, it just serializes the property names exactly as-is. To make it work with Flurl you can either create a class and decorate it with Json.NET serialization attributes, or (what I typically do) keep it simple take some liberties with C# property name conventions:

    .SetQueryParams(
        new
        {
            grant_type = "client_credentials",
            scope = "requiredScope"
        }