applicationId uz neni povinne
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
using System.Net.Http;
|
||||
using IdokladSdk;
|
||||
using IdokladSdk.Authentication;
|
||||
using IdokladSdk.Authentication.Models;
|
||||
using IdokladSdk.Exceptions;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Idoklad.Client;
|
||||
|
||||
/// <summary>
|
||||
/// iDoklad <c>client_credentials</c> authentication that sends only <c>client_id</c> and
|
||||
/// <c>client_secret</c> (no <c>application_id</c>).
|
||||
///
|
||||
/// The official SDK's <see cref="ClientCredentialsAuthentication"/> mandates an applicationId and
|
||||
/// always posts <c>application_id</c>, but iDoklad's standard client_credentials grant does not
|
||||
/// require it. This implementation is used when the caller does not supply an ApplicationId.
|
||||
/// </summary>
|
||||
public sealed class ClientSecretAuthentication : IAuthentication
|
||||
{
|
||||
private const string Scope = "idoklad_api";
|
||||
|
||||
private readonly string _clientId;
|
||||
private readonly string _clientSecret;
|
||||
|
||||
public ClientSecretAuthentication(string clientId, string clientSecret)
|
||||
{
|
||||
_clientId = clientId;
|
||||
_clientSecret = clientSecret;
|
||||
}
|
||||
|
||||
public DokladConfiguration Configuration { get; set; } = default!;
|
||||
|
||||
public string RefreshToken => null!;
|
||||
|
||||
public bool UseRefreshToken { get => false; set { } }
|
||||
|
||||
public async Task<Tokenizer> GetTokenAsync(HttpClient httpClient, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var postData = new List<KeyValuePair<string, string>>
|
||||
{
|
||||
new("grant_type", "client_credentials"),
|
||||
new("client_id", _clientId),
|
||||
new("client_secret", _clientSecret),
|
||||
new("scope", Scope),
|
||||
};
|
||||
|
||||
// The SDK targets the v2 token endpoint (server/v2/connect/token), which mandates
|
||||
// application_id. Without an applicationId we use the classic endpoint
|
||||
// (server/connect/token), which authenticates with client_id + client_secret only.
|
||||
var tokenUrl = Configuration.IdentityServerTokenUrl.ToString()
|
||||
.Replace("/server/v2/connect/token", "/server/connect/token");
|
||||
|
||||
using var request = new HttpRequestMessage(HttpMethod.Post, tokenUrl)
|
||||
{
|
||||
Content = new FormUrlEncodedContent(postData),
|
||||
};
|
||||
|
||||
using var response = await httpClient.SendAsync(request, cancellationToken).ConfigureAwait(false);
|
||||
var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
|
||||
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
throw new IdokladAuthenticationException(content);
|
||||
}
|
||||
|
||||
var tokenizer = JsonConvert.DeserializeObject<Tokenizer>(content);
|
||||
if (tokenizer is null || string.IsNullOrEmpty(tokenizer.AccessToken))
|
||||
{
|
||||
var error = JsonConvert.DeserializeObject<AuthenticationError>(content);
|
||||
throw new IdokladAuthenticationException(error);
|
||||
}
|
||||
|
||||
// GrantType defaults to ClientCredentials (enum value 0), which is correct here.
|
||||
return tokenizer;
|
||||
}
|
||||
|
||||
public Task<Tokenizer> RefreshAccessTokenAsync(HttpClient httpClient, CancellationToken cancellationToken = default)
|
||||
=> GetTokenAsync(httpClient, cancellationToken);
|
||||
}
|
||||
Reference in New Issue
Block a user