ordercloud-api / ordercloud-dotnet-sdk

The official .NET SDK for the OrderCloud eCommerce platform
MIT License
15 stars 14 forks source link

Password grant flow results in "invalid_client: invalid client secret" #107

Closed ghost closed 1 year ago

ghost commented 1 year ago
var userClient = new OrderCloudClient(new OrderCloudClientConfig {
    ClientId = _userClientId,
    Username = _username,
    Password = _password,
    ApiUrl = "https://westeurope-sandbox.ordercloud.io",
    AuthUrl = "https://westeurope-sandbox.ordercloud.io",
    Roles = new[] { ApiRole.Shopper }
});

var resp = await userClient.AuthenticateAsync();

This code results in OrderCloud.SDK.OrderCloudException: invalid_client: invalid client secret. What does the client secret have to do with anything? Is the error message supposed to say invalid user password? (I'm positive the password is correct, so that shouldn't be the case either, but...)

By the way, is the above supposed to be a valid way of getting a user access token, or should I stick to using using a FullAccess client and ImpersonationConfigs instead?

tmenier commented 1 year ago

This looks valid. My only suggestion is to try being explicit about setting OrderCloudClientConfig.GrantType:

var userClient = new OrderCloudClient(new OrderCloudClientConfig {
    ClientId = _userClientId,
    GrantType = GrantType.Password,
    ...

Also just make absolute certain that neither _username nor _password is null or empty. Let us know if these suggestions work; if not, we'll investigate further.

crhistianramirez commented 1 year ago

Also if client secret is defined on the API client then it is a required parameter on all auth calls. Any chance you set that field by mistake?

ghost commented 1 year ago

Also if client secret is defined on the API client then it is a required parameter on all auth calls. Any chance you set that field by mistake?

I must have missed that detail! So yes, I did set a client secret, however not by mistake, but by ignorance.

Without removing the client secret from the API Client, setting ClientSecret before setting Password gives me the same error about an invalid client secret (presumably because the grant type depends on which one of the properties ClientSecret and Password is set last). I think the error message could be more helpful when attempting to use the password flow with an API Client for which a client secret has been set.

Setting Password before ClientSecret (which means the grant type is client credentials), I do get a valid response:

var userClient = new OrderCloudClient(new OrderCloudClientConfig {
    ClientId = _buyerSellerClientId,
    Username = _username,
    Password = _password,
    ClientSecret = _buyerSellerClientSecret,
    ApiUrl = "https://westeurope-sandbox.ordercloud.io",
    AuthUrl = "https://westeurope-sandbox.ordercloud.io",
    Roles = new[] { ApiRole.Shopper }
});

var resp = await userClient.AuthenticateAsync();

The question is, whose token is in resp.AccessToken at that point?

tmenier commented 1 year ago

You raise some good points. Best advice I can give is to be explicit with GrantType. The behavior you're seeing is emanating from API itself and not the SDK, but we're going to evaluate whether we're being too strict with this requirement. Will report back here once a decision has been made.

tmenier commented 1 year ago

Based on some internal discussions, this API behavior is by design. The advice is to not "multi-purpose" your API clients, essentially. If you set a ClientSecret, use that client only when authenticating with the client_credentials grant type, and create a separate client, without a ClientSecret, for use with password flows.