IdentityServer 3 returns invalid_client when trying to authenticate with Blazor

407 Views Asked by At

I have an old IdentityServer 3 implementation and I'm trying not to change it to a newer version, I have been trying to authenticate a Blazor wasm application with it and so far almost everything went fine

Blazor Program.cs

...
builder.Services.AddOidcAuthentication(options =>
{
    builder.Configuration.Bind("Local", options.ProviderOptions);
});

Blazor appsettings.json

{
  "Local": {
    "Authority": "https://localhost:44343/",
    "ClientId": "clientid",
    "RedirectUri": "https://localhost:7170/authentication/login-callback",
    "PostLogoutRedirectUri": "https://localhost:7170/authentication/logout-callback",
    "ResponseType": "code"
  }
}

just for testing purposes I added a new in memory client in my identityserver

IdentityServer 3 Clients

new Client {
  ClientName = "client",
    ClientId = "clientid",
    Enabled = true,
    AccessTokenType = AccessTokenType.Reference,
    Flow = Flows.AuthorizationCodeWithProofKey,
    RequireConsent = false,
    ClientSecrets = new List < Secret > {
      new Secret("secret".Sha256())
    },
    // where to redirect to after login
    RedirectUris = {
      "https://localhost:7170/authentication/login-callback",
      "https://localhost:7170/connect/authorize/callback"
    },

    // where to redirect to after logout
    PostLogoutRedirectUris = {
      "https://localhost:7170/authentication/logout-callback"
    },
    AllowAccessToAllScopes = true,
    AllowedScopes = new List < string > {
      Constants.StandardScopes.OpenId,
      Constants.StandardScopes.Profile,
      Constants.StandardScopes.Email,
      Constants.StandardScopes.Roles,
      "Api"
    }
}

I tried both with

Flow = Flows.AuthorizationCodeWithProofKey

and

Flow = Flows.AuthorizationCode

the problem is that when I try and login everything works fine until a /connect/token request is issued to which the server responds with invalid_client

I might have a clue on why this is happening but so far nothing I tried has done anything

as far as I know IdentityServer 3 requires the client secret and I didn't find a way around this so I tried to set it on the appsettings with:

"ClientSecret" : "secret"

but nothing changes

1

There are 1 best solutions below

0
6b60449be4a642eeb74795e88d3d72 On

IdentityServer3 requires a client secret even though it's optional for authorization code flow with PKCE extension. You can implement a custom ISecretParser to produce a placeholder client secret when none is present.

IdentityServer3 SecretlessPostBodySecretParser.cs

public class SecretlessPostBodySecretParser : ISecretParser
{
    private readonly IdentityServerOptions options;

    public SecretlessPostBodySecretParser(IdentityServerOptions options)
        => this.options = options;

    public async Task<ParsedSecret> ParseAsync(IDictionary<string, object> environment)
    {
        var context = new OwinContext(environment);
        // Get ReadRequestFormAsync implementation from:
        // https://github.com/IdentityServer/IdentityServer3/blob/2.6.3/source/Core/Extensions/InternalOwinExtensions.cs
        var body = await context.ReadRequestFormAsync();
        if (body == null) return null;

        var id = body.Get("client_id");
        if (string.IsNullOrWhiteSpace(id)) return null;
        if (id.Length > options.InputLengthRestrictions.ClientId) return null;

        var secret = body.Get("client_secret");
        if (!string.IsNullOrWhiteSpace(secret)) return null;

        return new ParsedSecret
        {
            Id = id,
            Credential = "not-specified",
            Type = Constants.ParsedSecretTypes.SharedSecret
        };
    }
}

IdentityServer3 Startup.cs

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        var serviceFactory = new IdentityServerServiceFactory();
        serviceFactory.SecretParsers.Add(new Registration<ISecretParser, SecretlessPostBodySecretParser>());
        ...

        app.UseIdentityServer(new IdentityServerOptions
        {
            Factory = serviceFactory,
            ...
        });
    }
}

IdentityServer3 Client

new Client
{
    ClientSecrets = new List<Secret>
    {
        new Secret("not-specified".Sha256())
    },
    ...
}