---
title: Explicit credential authentication
summary: Validates explicit credentials and replaces the current thread principal on success.
status: draft
owner: <owner>
last_reviewed: 2026-07-30
library: SAIF.Framework.Security
reference_type: package
operation_id: OP-002
trigger: Caller sets `UserName` / `Domain` / `Password` and invokes `Authenticate()`
---

# Explicit credential authentication

Where principal initialization trusts whatever identity the host process or Forms cookie already provides, this operation instead validates a username, domain, and password that the caller supplies directly. It performs a Win32 logon against those credentials, converts the resulting token into a managed Windows principal, and — only on success — impersonates the authenticated identity so subsequent work runs in that user's security context.

| Field | Value |
| --- | --- |
| **Operation ID** | OP-002 |
| **Trigger** | Caller sets `UserName` / `Domain` / `Password` and invokes `Authenticate()` |
| **Inputs** | Principal credential fields |
| **Outputs** | Boolean success flag, updated thread principal, impersonation context on success |
| **Primary components** | `clsSecurityPrincipal.Authenticate`, `clsSecurityPrincipal.GetToken` |
| **Entry point** | `SAIF.Framework.Security\clsSecurityPrincipal.vb` |

## Steps

1. Each credential property setter (`UserName`, `Domain`, `Password`) updates its stored value and immediately calls `Logout()` first, so a new authentication attempt never starts on top of stale state — this enforces [BR-006](../business-rules.md#br-006-changing-identity-properties-logs-the-principal-out).
   - If a prior impersonation existed: `Logout()` undoes it before the setter returns, so the credential change takes effect on a clean principal.
2. `Authenticate()` calls `GetToken(UserName, Domain, Password)` to obtain a Windows access token for the supplied credentials.
   - `GetToken()` invokes Win32 `LogonUser`, duplicates the token it returns, closes the original handle, and throws a `could not logon` error if the logon call fails or the resulting token handle is invalid.
3. `Authenticate()` wraps that call in a try/catch: any token-acquisition failure is caught, and the method returns `False` immediately without touching the current thread principal.
4. When the token is acquired successfully, `Authenticate()` builds a `WindowsIdentity` and `WindowsPrincipal` from it, assigns them to `Thread.CurrentThread.CurrentPrincipal`, records the identity as the principal's new base identity, impersonates it, and marks the principal authenticated — all as one atomic outcome.
   - If the method returns `True`: the caller now holds an authenticated, impersonated principal that can flow directly into [Programmatic authorization checks](../security-authorization.md#programmatic-authorization-checks).

## Process flow

The following diagram visualizes this operation's control flow.

```mermaid
flowchart TD
	Start([Authenticate called]) --> Reset[Credential setters clear prior state]
	Reset --> Token[Acquire Win32 token]
	Token --> Success{Token acquired?}
	Success -->|No| EndErr([Return False])
	Success -->|Yes| Principal[Create Windows principal]
	Principal --> Imp[Impersonate identity]
	Imp --> EndOk([Return True])
```

## Failure and edge-case behavior

- Invalid credentials cause `GetToken()` to throw, which `Authenticate()` catches and converts into a `False` return rather than propagating the exception.
- There is no partial-success path: principal replacement and impersonation always happen together, and a caller only ever sees `True` after both steps have completed.

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

## Sources
- `SAIF.Framework.Security\clsSecurityPrincipal.vb`
