---
title: UserAuthenticator
summary: API reference for UserAuthenticator.
status: draft
owner: <owner>
last_reviewed: 2026-07-23
library: SAIF.Framework.SecurityModule
reference_type: package
---

# UserAuthenticator

`UserAuthenticator` is an abstract (`MustInherit`) base class that defines the authenticator strategy contract and provides two shared static helpers: authenticator selection by host classification (`Find`) and the already-authenticated short-circuit check (`IsAuthenticated`). The concrete subclasses `ExternalUserAuthenticator` and `InternalUserAuthenticator` are declared in the same source file and implement the internal/external fallback behavior.

## Purpose
- Provide a factory (`Find`) that selects the appropriate concrete authenticator based on host classification (see [BR-002](../../business-rules.md#br-002-host-classification-as-external-drives-the-authentication-fallback-path)).
- Define the abstract `Authenticate(WebContext)` contract implemented by `ExternalUserAuthenticator` and `InternalUserAuthenticator`.
- Provide the shared `IsAuthenticated` check used to short-circuit re-authentication (see [BR-001](../../business-rules.md#br-001-already-authenticated-users-are-not-re-processed)).

## Context
- Namespace: `SAIF.Framework.SecurityModule`
- Assembly/package: `SAIF.Framework.SecurityModule` (packaged inside the `SAIF.BOF.Framework` NuGet package)

## Public members
| Member | Signature | Purpose |
| --- | --- | --- |
| `Find` | `Public Shared Function Find(host As String, externalHostNames As String) As UserAuthenticator` | Classifies `host` against `externalHostNames` (case-insensitive substring match) and returns a new `ExternalUserAuthenticator` or `InternalUserAuthenticator` instance. |
| `IsAuthenticated` | `Public Shared Function IsAuthenticated(user As IPrincipal) As Boolean` | Returns `true` when `user` is non-null and `user.Identity.IsAuthenticated` is `true`. |
| `Authenticate` | `Public MustOverride Sub Authenticate(WebContext As HttpApplication)` | Abstract contract implemented by `ExternalUserAuthenticator` and `InternalUserAuthenticator` to perform the concrete authentication attempt and fallback. |

### ExternalUserAuthenticator (subclass)
| Member | Signature | Purpose |
| --- | --- | --- |
| `LoginPage` | `Public ReadOnly Property LoginPage As String` | Configured login page URL (`sec-loginpage` app setting), defaulting to `/onlinelogin/loginscreen.aspx`. |
| `Authenticate` | `Public Overrides Sub Authenticate(WebContext As HttpApplication)` | Attempts `CookieAuthenticator.Authenticate`; on failure, redirects the response to `LoginPage`. |

### InternalUserAuthenticator (subclass)
| Member | Signature | Purpose |
| --- | --- | --- |
| `Authenticate` | `Public Overrides Sub Authenticate(WebContext As HttpApplication)` | Attempts `CookieAuthenticator.Authenticate`; on failure, invokes `BrowserAuthenticator.Authenticate` with the `sec-browser-authtype` setting. |

## Behavioral notes
- `Find` performs an uppercase-normalized substring match (`If(externalHostNames, "").ToUpper().Contains(host.ToUpper())`), not an exact host-name comparison — any configured entry containing the host as a substring (or vice versa, since `Contains` is called on the settings string) causes external classification.*
- Both concrete subclasses delegate their cookie-authentication attempt to the shared static `CookieAuthenticator.Authenticate` method before applying their distinct fallback.

## Constraints and usage notes
- `UserAuthenticator` cannot be instantiated directly (`MustInherit`); callers obtain an instance exclusively via `Find`.
- `IsAuthenticated` and `Find` are `Shared` (static) members and do not require an instance.

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

## Sources
- `SAIF.Framework.SecurityModule\Authenticators\UserAuthenticator.vb`
