Back to Documentation
C# Documentation

C# Documentation

.NET/C# integration guide

Official GuideProduction Ready

C# SDK Guide

Dependencies

Add to your .csproj:

xml
<ItemGroup>
    <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
    <PackageReference Include="System.Net.Http" Version="4.3.4" />
</ItemGroup>

Or via NuGet Package Manager:

Install-Package Newtonsoft.Json

Basic Usage

csharp
using System;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Security.Cryptography;
using Newtonsoft.Json;

public class KeyClaimClient
{
    private readonly string apiKey;
    private readonly string secret;
    private readonly string baseUrl;
    private readonly HttpClient httpClient;

    public KeyClaimClient(string apiKey, string secret = null, string baseUrl = "https://keyclaim.org/api")
    {
        this.apiKey = apiKey;
        this.secret = secret ?? apiKey;
        this.baseUrl = baseUrl;
        this.httpClient = new HttpClient();
    }

    // Step 1: Create a challenge
    public async Task<ChallengeResponse> CreateChallengeAsync(int ttl = 30)
    {
        var requestBody = new
        {
            key = apiKey,
            ttl = ttl
        };

        var json = JsonConvert.SerializeObject(requestBody);
        var content = new StringContent(json, Encoding.UTF8, "application/json");

        var response = await httpClient.PostAsync($"{baseUrl}/challenge/create", content);
        response.EnsureSuccessStatusCode();

        var responseJson = await response.Content.ReadAsStringAsync();
        return JsonConvert.DeserializeObject<ChallengeResponse>(responseJson);
    }

    // Step 2: Generate response from challenge
    // Option A: Simple echo (for testing)
    public string GenerateResponseSimple(string challenge)
    {
        return challenge;
    }

    // Option B: HMAC-SHA256 (recommended)
    public string GenerateResponseHMAC(string challenge)
    {
        using (var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(secret)))
        {
            var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(challenge));
            return BitConverter.ToString(hash).Replace("-", "").ToLower();
        }
    }

    // Option C: SHA256 Hash
    public string GenerateResponseHash(string challenge)
    {
        using (var sha256 = SHA256.Create())
        {
            var hash = sha256.ComputeHash(Encoding.UTF8.GetBytes(challenge + secret));
            return BitConverter.ToString(hash).Replace("-", "").ToLower();
        }
    }

    // Step 3: Validate the response
    public async Task<ValidationResponse> ValidateAsync(string challenge, string response)
    {
        var requestBody = new
        {
            key = apiKey,
            challenge = challenge,
            response = response
        };

        var json = JsonConvert.SerializeObject(requestBody);
        var content = new StringContent(json, Encoding.UTF8, "application/json");

        try
        {
            var httpResponse = await httpClient.PostAsync($"{baseUrl}/challenge/validate", content);
            var responseJson = await httpResponse.Content.ReadAsStringAsync();
            var result = JsonConvert.DeserializeObject<ValidationResponse>(responseJson);
            
            if (!httpResponse.IsSuccessStatusCode)
            {
                result.Valid = false;
            }
            
            return result;
        }
        catch (Exception ex)
        {
            return new ValidationResponse
            {
                Valid = false,
                Error = ex.Message
            };
        }
    }

    // Complete example
    public async Task<ValidationResponse> ValidateChallengeAsync(string challenge, string method = "hmac")
    {
        string response = method switch
        {
            "echo" => GenerateResponseSimple(challenge),
            "hmac" => GenerateResponseHMAC(challenge),
            "hash" => GenerateResponseHash(challenge),
            _ => throw new ArgumentException($"Unknown method: {method}")
        };
        
        return await ValidateAsync(challenge, response);
    }

    // Response classes
    public class ChallengeResponse
    {
        [JsonProperty("challenge")]
        public string Challenge { get; set; }

        [JsonProperty("expires_in")]
        public int ExpiresIn { get; set; }
    }

    public class ValidationResponse
    {
        [JsonProperty("valid")]
        public bool Valid { get; set; }

        [JsonProperty("error")]
        public string Error { get; set; }

        [JsonProperty("signature")]
        public string Signature { get; set; }
    }
}

Usage Example

csharp
using System;
using System.Threading.Tasks;

class Program
{
    static async Task Main(string[] args)
    {
        var client = new KeyClaimClient(
            apiKey: "kc_your_api_key",
            secret: "your-secret-key"
        );

        try
        {
            // Create challenge
            var challengeResp = await client.CreateChallengeAsync(ttl: 30);
            var challenge = challengeResp.Challenge;
            Console.WriteLine($"Challenge: {challenge}");

            // Generate response
            var response = client.GenerateResponseHMAC(challenge);
            Console.WriteLine($"Response: {response}");

            // Validate
            var result = await client.ValidateAsync(challenge, response);
            Console.WriteLine($"Valid: {result.Valid}");
            
            if (result.Valid)
            {
                Console.WriteLine("✓ Challenge validated successfully!");
                if (!string.IsNullOrEmpty(result.Signature))
                {
                    Console.WriteLine($"Signature: {result.Signature}");
                }
            }
            else
            {
                Console.WriteLine($"✗ Validation failed: {result.Error}");
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error: {ex.Message}");
        }
    }
}

Response Generation Methods

Method 1: Echo (Testing)

csharp
public string GenerateResponseEcho(string challenge)
{
    return challenge;
}

Method 2: HMAC-SHA256 (Recommended)

csharp
public string GenerateResponseHMAC(string challenge)
{
    using (var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(secret)))
    {
        var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(challenge));
        return BitConverter.ToString(hash).Replace("-", "").ToLower();
    }
}

Method 3: SHA256 Hash

csharp
public string GenerateResponseHash(string challenge)
{
    using (var sha256 = SHA256.Create())
    {
        var hash = sha256.ComputeHash(Encoding.UTF8.GetBytes(challenge + secret));
        return BitConverter.ToString(hash).Replace("-", "").ToLower();
    }
}