Shared secrets is by far the most common technique for authenticating clients.
From a security point of view they have some shortcomings
The following snippet creates a shared secret.
var secret = new Secret("good_high_entropy_secret".Sha256());
By default it is assumed that every shared secret is hashed either using SHA256 or SHA512. If you load from a data store, your IdentityServer would store the hashed version only, whereas the client needs access to the plain text version.
You can either send the client id/secret combination as part of the POST body::
POST /connect/token
Content-type: application/x-www-form-urlencoded
client_id=client&
client_secret=secret&
grant_type=authorization_code&
code=hdh922&
redirect_uri=https://myapp.com/callback
..or as a basic authentication header::
POST /connect/token
Content-type: application/x-www-form-urlencoded
Authorization: Basic xxxxx
client_id=client1&
client_secret=secret&
grant_type=authorization_code&
code=hdh922&
redirect_uri=https://myapp.com/callback
You can use the IdentityModel client library to programmatically interact with the protocol endpoint from .NET code.
using IdentityModel.Client;
var client = new HttpClient();
var response = await client.RequestAuthorizationCodeTokenAsync(new AuthorizationCodeTokenRequest
{
Address = TokenEndpoint,
ClientId = "client",
ClientSecret = "secret",
Code = "...",
CodeVerifier = "...",
RedirectUri = "https://app.com/callback"
});