> ## Documentation Index
> Fetch the complete documentation index at: https://docs.diyanet.pro/llms.txt
> Use this file to discover all available pages before exploring further.

# Authenticator Servisi (TOTP)

> OtpNet ile RFC 6238 TOTP — secret üretimi, otpauth:// QR URI ve drift toleranslı doğrulama.

Authenticator servisi `src/DiyanetCleanArchitecture.Infrastructure.Services.Authenticator` projesindedir. Google Authenticator / Microsoft Authenticator gibi uygulamalarla uyumlu **TOTP** (Time-based One-Time Password, RFC 6238) üretir ve doğrular. Altında [OtpNet](https://github.com/kspearrin/Otp.NET) kütüphanesi çalışır.

## Arayüz

```csharp theme={null}
public interface IAuthenticationTotpService
{
    string GenerateSecret();
    string GenerateQrCodeUri(string accountName, string secret);
    bool   VerifyCode(string secret, string code, DateTime utcNow, out long timeStep);
}
```

## Secret üretimi

`GenerateSecret`, config'teki `SecretLength` (default 20 byte = 160 bit) uzunluğunda rastgele anahtar üretir ve Base32 kodlar:

```csharp theme={null}
public string GenerateSecret()
{
    var key = KeyGeneration.GenerateRandomKey(_options.SecretLength);
    return Base32Encoding.ToString(key);
}
```

## QR Code URI — `otpauth://`

`GenerateQrCodeUri`, authenticator uygulamalarının okuduğu standart `otpauth://totp/...` URI'sini üretir. Issuer ve account adı URL-encode edilir; algoritma, basamak ve periyot config'ten gelir:

```csharp theme={null}
return
    $"otpauth://totp/{encodedIssuer}:{encodedAccount}" +
    $"?secret={secret}" +
    $"&issuer={encodedIssuer}" +
    $"&algorithm={_options.Algorithm}" +   // SHA1
    $"&digits={_options.Digits}" +         // 6
    $"&period={_options.TimeStepSeconds}"; // 30
```

## Doğrulama — drift toleransı

`VerifyCode`, kodu Base32 secret ile doğrular. Saat kayması için `AllowedDriftSteps` kadar (default ±1 time step) pencere uygulanır. Eşleşen `timeStep` `out` parametresiyle döner (replay/önceki kullanım kontrolü için):

```csharp theme={null}
var totp = new Totp(secretBytes,
    step: _options.TimeStepSeconds,
    totpSize: _options.Digits,
    mode: _hashMode);

var window = new VerificationWindow(
    previous: _options.AllowedDriftSteps,
    future:   _options.AllowedDriftSteps);

return totp.VerifyTotp(code, out timeStep, window);
```

<Note>
  Servis **fail-closed**'dur: geçersiz Base32, sayısal olmayan kod ya da beklenmedik herhangi bir hata `false` döner — asla "doğru" kabul etmez.
</Note>

Constructor'da seçenekler validate edilir: `Issuer` boş olamaz, `TimeStepSeconds > 0`, `SecretLength >= 16`, `AllowedDriftSteps >= 0`, `Digits ∈ {4, 6, 8}`, `Algorithm ∈ {SHA1, SHA256, SHA512}`.

## User aggregate ile ilişki

Servis yalnızca saf TOTP hesaplaması yapar; durum **User aggregate**'inde tutulur. Akış (`ConfigureTotpCommandHandler`):

```csharp theme={null}
var plainSecret   = _totpService.GenerateSecret();
var encryptedSecret = TotpSecret.Create(encrypted: _secretProtector.Protect(plainSecret));

user.ConfigureTotp(encryptedSecret);                          // aggregate'e işle
var qrCodeUri = _totpService.GenerateQrCodeUri(user.Phone.Value, plainSecret);

await _unitOfWork.SaveEntitiesAsync(cancellationToken);
// dön: { ManualEntryKey = plainSecret, QrCodeUri = qrCodeUri }
```

User aggregate metodları: `ConfigureTotp` (secret atar, henüz aktif değil), `EnableTotp` (ilk doğru kod ile etkinleştirir), `VerifyTotp`, `DisableTotp`.

<Warning>
  **`TotpSecret` DataProtection ile şifreli saklanır.** `ITotpSecretProtector` (impl: `TotpSecretProtector`) ASP.NET Core `IDataProtectionProvider`'ı `"TotpSecret"` purpose'u ile kullanır. DB'ye düz secret asla yazılmaz; QR/manuel giriş için düz secret yalnızca configure anında, response'da bir kez döner.
</Warning>

## Config — `Services:Authenticator`

```json theme={null}
{
  "Services": {
    "Authenticator": {
      "Issuer": "DiyanetCleanArchitecture",
      "TimeStepSeconds": 30,
      "AllowedDriftSteps": 1,
      "SecretLength": 20,
      "Algorithm": "SHA1",
      "Digits": 6
    }
  }
}
```

<ParamField path="Issuer" type="string" default="DiyanetCleanArchitecture">Authenticator uygulamasında görünen sağlayıcı adı.</ParamField>
<ParamField path="TimeStepSeconds" type="int" default="30">TOTP periyodu (RFC 6238 standardı = 30 sn).</ParamField>
<ParamField path="AllowedDriftSteps" type="int" default="1">Saat kayması toleransı (±N adım).</ParamField>
<ParamField path="SecretLength" type="int" default="20">Secret uzunluğu (byte). Min 16.</ParamField>
<ParamField path="Algorithm" type="string" default="SHA1">SHA1 / SHA256 / SHA512. Uyumluluk için SHA1.</ParamField>
<ParamField path="Digits" type="int" default="6">Kod basamak sayısı (4, 6 veya 8).</ParamField>

## DI kaydı

```csharp theme={null}
public static IServiceCollection AddAuthenticatorService(this IServiceCollection services, IConfiguration configuration)
{
    services.Configure<AuthenticatorServiceOptions>(o =>
        configuration.GetSection("Services:Authenticator").Bind(o));

    services.AddScoped<IAuthenticationTotpService, AuthenticationTotpService>();
    return services;
}
```

<CardGroup cols={2}>
  <Card title="User Aggregate" icon="user" href="/domain/aggregates">
    `ConfigureTotp / EnableTotp / VerifyTotp` metodları ve `TotpSecret` value object.
  </Card>

  <Card title="Güvenlik" icon="shield" href="/security/overview">
    Çok faktörlü kimlik doğrulama ve DataProtection kullanımı.
  </Card>
</CardGroup>
