---
title: Issue the legacy auth cookie
summary: Encrypts a user's credentials with DPAPI and writes the SAIFAUTH response cookie.
status: draft
owner: Framework
last_reviewed: 2026-10-02
library: SAIF.NetCore.LegacyAuth
reference_type: package
operation_id: OP-01
trigger: A consuming application calls SetCookie(user, password) after the user has authenticated.
---

# Issue the legacy auth cookie

This operation builds the tab-delimited credential payload, encrypts it with Windows DPAPI, and writes the resulting value as the `SAIFAUTH` response cookie so a legacy .NET Framework "SecurityModule" can authenticate the user on the same host.

| Field | Value |
| --- | --- |
| **Operation ID** | OP-01 |
| **Trigger** | A consuming application calls it after the user has authenticated, inferred to be while the plaintext password is still available* |
| **Inputs** | `user`, `password`; the ambient `HttpContext` from `IHttpContextAccessor` |
| **Outputs** | A `Set-Cookie: SAIFAUTH=<base64>; path=/; httponly` header appended to the current response. Returns `void`. |
| **Primary components** | `LegacyAuthCookieService.SetCookie` |
| **Entry point** | `src/SAIF.NetCore.LegacyAuth/src/SAIF.NetCore.LegacyAuth/SAIF.NetCore.LegacyAuth/LegacyAuthCookieService.cs` |

## Steps

1. Read the current `HttpContext` from `_httpContextAccessor.HttpContext`.
   - On failure: outside an active request, `context` is `null` and the next step throws `NullReferenceException` ([BR-10](../business-rules.md#br-10-active-http-request-required-for-cookie-operations))
2. Build the plaintext payload `"{user}\t{password}\t"` ([BR-02](../business-rules.md#br-02-tab-delimited-credential-payload))
   - Null `user`/`password` interpolate as empty strings; a tab character embedded in either value is not escaped and may corrupt the legacy reader's parsing*.
3. Take the client's remote IP address as a string to use as DPAPI entropy ([BR-03](../business-rules.md#br-03-client-ip-as-encryption-entropy))
   - On failure: `RemoteIpAddress` can be `null` under some in-process hosts, producing `NullReferenceException` ([BR-10](../business-rules.md#br-10-active-http-request-required-for-cookie-operations))
4. Encrypt the payload with DPAPI using the machine key scope, the IP entropy, and an empty description ([BR-04](../business-rules.md#br-04-machine-scope-dpapi-encryption))
   - 4.1 Apply defaults through the overload chain down to the four-argument `Encrypt(KeyType, string, string, string)` call ([BR-07](../business-rules.md#br-07-instance-encrypt-defaults-to-user-key-scope))
   - 4.2 Coerce a `null` plaintext or entropy argument to `""` ([BR-08](../business-rules.md#br-08-null-inputs-coerced-to-empty-values))
   - 4.3 UTF-8 encode the plaintext and entropy, then Base64-encode the returned ciphertext ([BR-09](../business-rules.md#br-09-utf-8-and-base64-encoding-for-string-encryption))
   - On failure: any exception raised inside the byte-array encrypt call's own try block is rethrown as `Exception("DPAPI was unable to encrypt data.")` ([BR-12](../business-rules.md#br-12-generic-exception-wrapping-on-encryption-failure)); failures in UTF-8/Base64 conversion or argument coercion outside that try block propagate unwrapped.

   > **Origin**: Steps 4.1–4.3 are implemented in [Encrypt a string with DPAPI](encrypt-string-with-dpapi.md) and executed on behalf of this operation.
5. Write the encrypted Base64 value as the `SAIFAUTH` cookie ([BR-01](../business-rules.md#br-01-fixed-cookie-name-saifauth), [BR-05](../business-rules.md#br-05-no-url-encoding-on-cookie-value), [BR-06](../business-rules.md#br-06-cookie-attributes-omit-secure-and-samesite))
   - 5.1 Create a `SetCookieHeaderValue(key, value)` with `Path = "/"` and `HttpOnly = true`.
   - 5.2 Render it to a header string with no URL-encoding.
   - 5.3 Append the string to any existing `Set-Cookie` values with `StringValues.Concat`.

   > **Origin**: Steps 5.1–5.3 are implemented in [Append a raw Set-Cookie header](append-raw-set-cookie-header.md) and executed on behalf of this operation.

## Process flow

The following diagram visualizes this operation's control flow, including the embedded encrypt and header-write sub-operations.

```mermaid
flowchart TD
    Start(["Trigger: SetCookie called"]) --> S1["Read HttpContext<br>from accessor"]
    S1 --> D1{HttpContext null?}
    D1 -->|Yes| ErrNull1([NullReferenceException])
    D1 -->|No| S2["Build payload:<br>user + TAB + password + TAB"]
    S2 --> S3["Read client remote IP<br>as DPAPI entropy"]
    S3 --> D2{RemoteIpAddress null?}
    D2 -->|Yes| ErrNull2([NullReferenceException])
    D2 -->|No| S4["Encrypt with DPAPI:<br>MachineKey scope + IP entropy"]
    S4 --> D3{Encryption failed?}
    D3 -->|Yes| ErrEnc(["Exception:<br>unable to encrypt data"])
    D3 -->|No| S5["Write Set-Cookie SAIFAUTH<br>header, raw Base64"]
    S5 --> EndOk([Set-Cookie header written])
```

## Failure and edge-case behavior
- Calling `SetCookie` outside an active HTTP request, or when `RemoteIpAddress` is unavailable, throws `NullReferenceException` before any cookie is written ([BR-10](../business-rules.md#br-10-active-http-request-required-for-cookie-operations))
- An exception raised inside the byte-array encrypt call's own try block — including running on a non-Windows host or a non-default Windows installation directory — is wrapped as a generic `System.Exception("DPAPI was unable to encrypt data.")` ([BR-12](../business-rules.md#br-12-generic-exception-wrapping-on-encryption-failure), [BR-13](../business-rules.md#br-13-windows-only-dpapi-dll-path)). UTF-8/Base64 conversion in this operation's string payload handling, and argument coercion that runs before that try block, are not wrapped by this rule.
- A tab character embedded in `user` or `password` is not escaped and may corrupt the legacy reader's parsing of the payload ([BR-02](../business-rules.md#br-02-tab-delimited-credential-payload))

## Related documentation
- [Operations and processes](../operations-processes.md)
- [Business rules](../business-rules.md)

> **Note:** Statements marked with `*` were inferred from code structure, naming
> conventions, or contextual evidence where direct confirmation was not available
> in source artifacts.

## Sources
- `src/SAIF.NetCore.LegacyAuth/src/SAIF.NetCore.LegacyAuth/SAIF.NetCore.LegacyAuth/LegacyAuthCookieService.cs`
