---
title: SAIF.NetCore.AuthService security and authorization
summary: Authorization requirements, AD resource catalog, security enforcement points, and security observations.
status: draft
owner: Framework.NCore maintainers
last_reviewed: 2026-10-02
library: SAIF.NetCore.AuthService
reference_type: package
---

# SAIF.NetCore.AuthService security and authorization

This page documents authorization mechanisms implemented or consumed by this library. Authentication is wired by this library (JWT Bearer / IIS Windows / dual scheme selection) but is delegated entirely to ASP.NET Core authentication handlers; this page records authentication only where it determines the identity value fed into an authorization decision. The library itself defines **no controllers, endpoints, or `[Authorize]`/`[AllowAnonymous]` usages** — it is a mechanism provider that a consuming application must register and apply.

## Authorization architecture

Role and resource decisions are delegated to a remote REST "SecurityApi" via `ISecurityClient.IsAuthorized`, reached either through the declarative `[SecurityApiAuthorize]` pipeline or directly by consumer code; `TokenIdentityService` additionally accepts a matching token role claim as a local shortcut before falling back to the remote call, and `IsAuthorized(Predicate<Claim>)` is purely local with no remote call at all. There is no WCF SecurityService integration, no direct AD/LDAP access, no data-level authorization, and no segregation-of-duties enforcement in this library ([BR-AUTH-004](business-rules.md#br-auth-004-securityapiauthorize-maps-roles-to-a-dynamic-policy-name) through [BR-AUTH-011](business-rules.md#br-auth-011-a-non-successful-securityapi-response-always-throws)).

```mermaid
flowchart TD
    Attr["[SecurityApiAuthorize roles]"] --> Policy[SecurityApiPolicy]
    Policy --> Req[SecurityApiRequirement]
    Req --> Handler["SecurityApiHandler (Singleton, OR over roles)"]
    Handler -->|"user = Identity.Name minus DOMAIN\"| Client1[ISecurityClient.IsAuthorized]
    Accessor[IIdentityServiceAccessor] --> Token[TokenIdentityService.IsAuthorized]
    Accessor --> Win[WinIdentityService.IsAuthorized]
    Token -->|"IsInRole(role) == true"| LocalOK[Authorized locally - no remote call]
    Token -->|"IsInRole(role) == false"| Client2["ISecurityClient.IsAuthorized(mailid claim, role)"]
    Win --> Client3["ISecurityClient.IsAuthorized(DOMAIN/user, role)"]
    Client1 --> Suffix["Resource-suffix rewrite (SecurityClient:resourcesuffix)"]
    Client2 --> Suffix
    Client3 --> Suffix
    Suffix --> API["GET {SecurityClient:ServiceUrl}<br>/v1/Users/IsAuthorized/{user}/{role'}"]
    API -->|non-success| Throw[Throw SecurityClientException]
```

## AD resource catalog

**No AD group or resource-name literals exist in the library code** — every role/resource name is supplied by the caller at run time, either as the `[SecurityApiAuthorize(roles)]` argument or as the `role` parameter of `IIdentityService.IsAuthorized(string)`/`ISecurityClient.IsAuthorized(userId, role)`.

| Resource name | Purpose | Enforcement point | Source |
| --- | --- | --- | --- |
| *(none hard-coded)* | Role names are caller-supplied. | `SecurityApiAuthorize` ctor; `SecurityApiHandler.HandleRequirementAsync`; `TokenIdentityService.IsAuthorized`; `WinIdentityService.IsAuthorized`; `SecurityClient.IsAuthorized` | `src/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/Authorization/SecurityApiAuthorize.cs`; `src/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/Authorization/SecurityApiHandler.cs`; `src/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/Identity/TokenIdentityService.cs`; `src/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/Identity/WinIdentityService.cs`; `src/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/Clients/SecurityClient.cs` |

### Resource-name transformation (environment suffix convention)

The library implements the SAIF `Resource`/`TestResource` environment-suffix convention on the client side, before calling the SecurityApi: a trimmed role ending in `resource` (case-insensitive) has the **last** occurrence of `resource` replaced with the configured `SecurityClient:resourcesuffix` value; roles not ending in `resource` pass through unchanged ([BR-AUTH-010](business-rules.md#br-auth-010-environment-resource-suffix-rewrite)). This transformation *replaces* a trailing `resource` token rather than appending a suffix to a base name — consumers must pass the full production resource name (for example `Resource`, not a shortened form), and the library substitutes the configured suffix for that trailing token. The per-environment `resourcesuffix` value itself is environment configuration and is not present in this repository**.

### AD group names seen outside the library (consumers / test hosts — not library behavior)

| Name | Where | Kind |
| --- | --- | --- |
| `Domain Users` | `AuthTestController.Authorized` | AuthService integration-test host (not shipped library surface) |
| `Domain Users`, `Developer_Group`, `Users` | `AuthController`, `ValuesController` | ServiceExtensions integration tests (not shipped library surface) |

No direct AD/LDAP access exists in this library — no `System.DirectoryServices`/`System.DirectoryServices.AccountManagement` usage, no `PrincipalContext`/`GroupPrincipal`/`DirectoryEntry`/`DirectorySearcher`, and no LDAP strings. All AD questions are delegated to the remote SecurityApi over HTTP through `ISecurityClient`'s five operations: `IsAuthorized`, `GetUser`/`GetUser<T>`, `GetUsersByGroup`, `GetAuthorizationGroups`, and `GetExternalUser`; only `IsAuthorized` makes an authorization decision inside the library.

## Authorization enforcement points

Required registrations for the attribute-based enforcement points (EP-01 through EP-04) to take effect are `services.AddSecurityApiAuthorizeAttribute()` plus `AddAuthorization()` in the consumer, and an identity registration (`AddTokenIdentityService`/`AddWinIdentityService`/`AddIdentityAccessor`). The programmatic checks (EP-05 through EP-08) call `TokenIdentityService`/`WinIdentityService`/`SecurityClient` members directly and do not require `AddSecurityApiAuthorizeAttribute()` or the declarative attribute/policy pipeline — only an identity or `ISecurityClient` registration.

### Attribute-based authorization

| # | Element | Kind | Behavior | Source |
| --- | --- | --- | --- | --- |
| EP-01 | `[SecurityApiAuthorize(string roles)]` | Attribute, derives from `AuthorizeAttribute` | Sets `Policy = "SecurityAPI.{roles}"`; `roles` is a comma-separated list; usable on controller or action ([BR-AUTH-004](business-rules.md#br-auth-004-securityapiauthorize-maps-roles-to-a-dynamic-policy-name)) | `src/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/Authorization/SecurityApiAuthorize.cs` |
| EP-02 | `SecurityApiPolicy` | `IAuthorizationPolicyProvider`, registered Transient | For a policy name `Length > 1` starting with `SecurityAPI`, builds a policy containing only `SecurityApiRequirement(roles)`; no `RequireAuthenticatedUser()`, no authentication schemes added; all other names delegate to `DefaultAuthorizationPolicyProvider` ([BR-AUTH-005](business-rules.md#br-auth-005-securityapi-prefixed-policy-names-resolve-to-a-securityapirequirement)) | `src/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/Authorization/SecurityAPIPolicy.cs` |
| EP-03 | `SecurityApiRequirement` | `IAuthorizationRequirement` | Carries the `ProvidedRoles` string, read-only after construction. | `src/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/Authorization/SecurityApiRequirement.cs` |
| EP-04 | `SecurityApiHandler` | `AuthorizationHandler<SecurityApiRequirement>`, registered Singleton | Returns without succeeding if `Identity.Name` is null/whitespace — an empty-name guard, not a check of `Identity.IsAuthenticated` ([BR-AUTH-006](business-rules.md#br-auth-006-an-unnamed-identity-never-satisfies-a-securityapi-requirement)); strips the domain from `Identity.Name` by taking the second `\`-delimited segment ([BR-AUTH-007](business-rules.md#br-auth-007-the-handler-strips-the-windows-domain-before-calling-the-securityapi)); for each role in `ProvidedRoles` calls `ISecurityClient.IsAuthorized`, succeeding on any `true` with no short-circuit ([BR-AUTH-008](business-rules.md#br-auth-008-comma-separated-roles-use-or-semantics)); never calls `context.Fail()`. Authentication itself is performed by the host's ASP.NET Core authentication handler, not by this handler; whether a host can ever present a non-empty `Identity.Name` for an unauthenticated principal is a host/policy assumption not verified here**. | `src/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/Authorization/SecurityApiHandler.cs` |

Decision path: `[SecurityApiAuthorize("A,B")]` → policy `SecurityAPI.A,B` → `SecurityApiPolicy` → `SecurityApiRequirement("A,B")` → `SecurityApiHandler` → `SecurityClient.IsAuthorized(user, "A")`, then `"B"` → resource-suffix rewrite → `GET {ServiceUrl}/v1/Users/IsAuthorized/{user}/{role'}`.

### Programmatic authorization checks

| # | Member | Resource / Role | Check type | Behavior | Source |
| --- | --- | --- | --- | --- | --- |
| EP-05 | `TokenIdentityService.IsAuthorized(string role)` | caller-supplied | Local-first, remote fallback | Local: `User.IsInRole(role)` returns `true` with no remote call. Remote fallback: `SecurityClient.IsAuthorized(UserId, role)` where `UserId` is the `mailid` claim value ([BR-AUTH-013](business-rules.md#br-auth-013-token-users-can-authorize-locally-via-a-role-claim)) | `src/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/Identity/TokenIdentityService.cs` |
| EP-06 | `WinIdentityService.IsAuthorized(string role)` | caller-supplied | Always remote | `SecurityClient.IsAuthorized(UserId, role)` where `UserId` is the full `DOMAIN\user` ([BR-AUTH-014](business-rules.md#br-auth-014-windows-user-id-keeps-the-domain-and-is-always-remote)) No local `IsInRole` check. | `src/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/Identity/WinIdentityService.cs` |
| EP-07 | `BaseIdentityService.IsAuthorized(Predicate<Claim>)` | caller-supplied predicate | Local only | `Identity.HasClaim(match)`; no remote call and no resource-suffix rewrite. | `src/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/Identity/BaseIdentityService.cs` |
| EP-08 | `SecurityClient.IsAuthorized(userId, role)` | caller-supplied | Direct remote client call | `\` → `/` on the user ID; resource-suffix rewrite; `GET` to `/v1/Users/IsAuthorized/{userId}/{role}`; returns the deserialized `bool`; a non-success response throws `SecurityClientException` — no default-deny `false` ([BR-AUTH-009](business-rules.md#br-auth-009-backslashes-in-user-ids-are-rewritten-to-forward-slashes), [BR-AUTH-011](business-rules.md#br-auth-011-a-non-successful-securityapi-response-always-throws)). Used directly by EP-04/05/06 and by external consumers such as `SAIF.NetCore.NtlmApiAuth`*. | `src/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/Clients/SecurityClient.cs` |
| EP-09 | `MultiIdentityServiceAccessor.IdentityService` / `IdentityServiceAccessor.IdentityService` | n/a | Identity selection | Determines which of EP-05/EP-06 (and therefore which user-ID rule) applies. Multi: `AuthenticationSchemeSelector(HttpContext)` — a `Bearer ` header resolves `TokenIdentityService`, anything else resolves `WinIdentityService`; with no `HttpContext`, resolves `WinIdentityService` ([BR-AUTH-016](business-rules.md#br-auth-016-no-httpcontext-defaults-the-multi-accessor-to-windows)) Single: whatever `IIdentityService` is registered. | `src/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/Identity/MultiIdentityServiceAccessor.cs`; `src/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/Identity/IdentityServiceAccessor.cs`; `src/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/Extensions/AuthenticationServiceExtensions.cs` |

**Enforcement-to-resource mapping:**

| Enforcement point | Resource source | Suffix rewrite applied? | Decision authority |
| --- | --- | --- | --- |
| EP-01→EP-04 (attribute path) | Attribute argument (consumer code) | Yes (inside `SecurityClient`) | Remote SecurityApi |
| EP-05 (token) | `role` argument (consumer code) | No for the local `IsInRole` short-circuit; yes for the remote fallback | Token role claim, then remote SecurityApi |
| EP-06 (Windows) | `role` argument (consumer code) | Yes | Remote SecurityApi |
| EP-07 (claims predicate) | Consumer predicate | No | Local token/identity claims |
| EP-08 (direct client) | Caller | Yes | Remote SecurityApi |

**In-repo consumers of these enforcement points (cross-reference only):**

| Consumer | Uses | Source |
| --- | --- | --- |
| `SAIF.NetCore.NtlmApiAuth` → `NtlmApiAuthorizationService` | `ISecurityClient.IsAuthorized(requestUser, role)` and `IsAuthorized(onBehalfOfUser, role)` | `src/SAIF.NetCore.NtlmApiAuth/src/SAIF.NetCore.NtlmApiAuth/Services/NtmlApiAuthorizationService.cs` |
| `SAIF.NetCore.ServiceExtensions` → `RegisterCoreAPIAuthServices`/`RegisterEdgeAPIAuthServices` | `AddIdentityAccessor().AddDualAuthentication()`, `AddSecurityApiAuthorizeAttribute()` | `src/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/IServiceCollectionExtensions.cs` |
| `SAIF.NetCore.ServiceExtensions` → `AppStartup` | `AddTransient<ISecurityClient, SecurityClient>()`, `AddIdentityAccessor()`, `AddSecurityApiAuthorizeAttribute()` | `src/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/Startup/AppStartup.cs` |

`AppStartup` registers `ISecurityClient` as Transient, while `SecurityApiHandler` is a library-registered Singleton — the Singleton handler therefore captures one `SecurityClient` instance for the process lifetime; this is believed harmless since `SecurityClient` is stateless after construction*, but it is a lifetime mismatch.

## Security interfaces and contracts

| Interface / Class | Role | Consumers | Source |
| --- | --- | --- | --- |
| `ISecurityClient` | Contract for the remote SecurityApi client (role authorization, user profile, group membership, authorization groups, external-user data) | `SecurityApiHandler`, `TokenIdentityService`, `WinIdentityService`, `SAIF.NetCore.NtlmApiAuth` | `src/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/Interfaces/ISecurityClient.cs` |
| `IAccessTokenClient` | Contract for an outbound OAuth client-credentials token client | Consumer code calling downstream APIs | `src/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/Interfaces/IAccessTokenClient.cs` |
| `BaseIdentityService` | Abstract base implementing `IIdentityService` (ServiceContracts); shared identity/claims surface | `TokenIdentityService`, `WinIdentityService` | `src/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/Identity/BaseIdentityService.cs` |
| `IdentityServiceAccessor`, `MultiIdentityServiceAccessor` | Implement `IIdentityServiceAccessor` (ServiceContracts); resolve the active `IIdentityService` for the current request | Consumer code via DI | `src/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/Identity/IdentityServiceAccessor.cs`; `src/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/Identity/MultiIdentityServiceAccessor.cs` |

## Security observations

### SEC-01 User-ID inconsistency between paths

| Field | Value |
| --- | --- |
| **Observation** | User-ID inconsistency between paths: the attribute path (EP-04) strips the domain from `Identity.Name`, `WinIdentityService` (EP-06) sends the full `DOMAIN\user`, and `TokenIdentityService` (EP-05) sends the `mailid` claim value — the same principal can reach the SecurityApi under different identifiers depending on the path; for JWT callers on the attribute path, `Identity.Name` depends on the JwtBearer `NameClaimType` mapping rather than `mailid`, so it may be empty (a deny) or a different value*. |
| **Severity** | Medium |
| **Source** | `src/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/Authorization/SecurityApiHandler.cs`; `src/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/Identity/WinIdentityService.cs`; `src/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/Identity/TokenIdentityService.cs` |

### SEC-02 Domain-agnostic attribute check

| Field | Value |
| --- | --- |
| **Observation** | Domain-agnostic attribute check: stripping the domain makes `DOMAINA\bob` and `DOMAINB\bob` indistinguishable on the attribute path; whether this matters depends on how the SecurityApi resolves a domain-less user**. |
| **Severity** | Medium |
| **Source** | `src/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/Authorization/SecurityApiHandler.cs` |

### SEC-03 Token role claims bypass the remote check and the suffix rewrite

| Field | Value |
| --- | --- |
| **Observation** | Token role claims bypass the remote check and the suffix rewrite: a matching `ClaimTypes.Role` claim grants access locally in `TokenIdentityService.IsAuthorized`, using the raw caller role string rather than the environment-suffixed one — trust in this path equals trust in the token issuer's role claims. |
| **Severity** | Low/Medium |
| **Source** | `src/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/Identity/TokenIdentityService.cs` |

### SEC-04 Fail-closed by exception, not by deny

| Field | Value |
| --- | --- |
| **Observation** | Fail-closed by exception, not by deny: a SecurityApi error throws `SecurityClientException` from inside the authorization handler or identity service, so the request fails with an unhandled exception (typically HTTP 500) rather than a 403 — access is not granted, but the failure mode differs from a normal deny. |
| **Severity** | Low |
| **Source** | `src/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/Clients/SecurityClient.cs` |

### SEC-05 Policy prefix capture

| Field | Value |
| --- | --- |
| **Observation** | Policy prefix capture: any policy name starting with `SecurityAPI` (current-culture, case-sensitive comparison via the single-argument `StartsWith(string)` overload, not ordinal) is intercepted; a name without `.` uses the whole policy name as the role string. |
| **Severity** | Low |
| **Source** | `src/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/Authorization/SecurityAPIPolicy.cs` |

### SEC-06 No explicit authenticated-user requirement in built policies

| Field | Value |
| --- | --- |
| **Observation** | No explicit authenticated-user requirement in built policies: `SecurityApiPolicy` builds a policy with only `SecurityApiRequirement`, and the generated policy never calls `RequireAuthenticatedUser()`. `SecurityApiHandler` (EP-04) only guards against a null/whitespace `Identity.Name`; it never inspects `Identity.IsAuthenticated`. This blocks requests with no name at all, but it does not by itself guarantee that every unauthenticated or anonymous caller is denied — that depends on whether the host's authentication pipeline can ever populate `Identity.Name` for an identity that is not authenticated, which is a host/policy assumption not verified from this library's source**. |
| **Severity** | Informational |
| **Source** | `src/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/Authorization/SecurityAPIPolicy.cs`; `src/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/Authorization/SecurityApiHandler.cs` |

### SEC-07 Unencoded route segments

| Field | Value |
| --- | --- |
| **Observation** | Unencoded route segments: user IDs, roles, domains, and group names are interpolated into URL paths with no URL encoding beyond `\` → `/`; roles containing spaces (e.g. `Domain Users`), `/`, `?`, or `#` change the request path or query sent to the SecurityApi; whether `IHttpJsonClient` encodes paths is outside this library**. |
| **Severity** | Low/Medium |
| **Source** | `src/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/Clients/SecurityClient.cs` |

### SEC-08 Global scheme-selector mutability

| Field | Value |
| --- | --- |
| **Observation** | Global scheme-selector mutability: `AuthenticationSchemeSelector` is a `public static` mutable field — reassigning it changes which identity service, and therefore which user-ID rule (EP-09), applies process-wide ([BR-AUTH-015](business-rules.md#br-auth-015-authorization-header-prefix-selects-the-dual-authentication-scheme)) |
| **Severity** | Low/Medium |
| **Source** | `src/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/Extensions/AuthenticationServiceExtensions.cs` |

### SEC-09 Unauthenticated or no-context default

| Field | Value |
| --- | --- |
| **Observation** | Unauthenticated / no-context default: with no `HttpContext`, `MultiIdentityServiceAccessor` returns `WinIdentityService` whose `UserId` is then `null`, and `SecurityClient.IsAuthorized` calls `userId.Replace("\\", "/")` on that `null`, which throws `NullReferenceException`* ([BR-AUTH-016](business-rules.md#br-auth-016-no-httpcontext-defaults-the-multi-accessor-to-windows)) |
| **Severity** | Low |
| **Source** | `src/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/Identity/MultiIdentityServiceAccessor.cs` |

### SEC-10 No authorization-result caching

| Field | Value |
| --- | --- |
| **Observation** | No authorization-result caching: each attribute evaluation makes one remote call per listed role without stopping after the first success, and there is no per-request or cross-request cache ([BR-AUTH-008](business-rules.md#br-auth-008-comma-separated-roles-use-or-semantics)) |
| **Severity** | Informational |
| **Source** | `src/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/Authorization/SecurityApiHandler.cs` |


## Notes
- A trailing `resource` token in a role name is replaced with the configured `SecurityClient:resourcesuffix` value at runtime; `Resource` and `TestResource` below are illustrative examples of that convention, not verified per-track values.
- No WCF SecurityService integration, direct AD/LDAP access, data-level authorization, segregation-of-duties enforcement, or machine/application AD authorization exists in this library; the outbound `OktaTokenClient`/`IAccessTokenClient` capability is application credentialing toward downstream services, not an inbound authorization check.
- Open items not resolvable from this repository: how the remote SecurityApi resolves a domain-less user and which AD domain it searches by default; the per-environment `SecurityClient:resourcesuffix` values; how `IHttpJsonClient` authenticates to the SecurityApi and whether it URL-encodes path segments; whether the domain stripping in `SecurityApiHandler` is intentional given `WinIdentityService` keeps the domain; whether the SecurityApi is backed by the same AD lookups as the BOF WCF SecurityService.

## Related documentation
- [Index](index.md)
- [Overview](overview.md)
- [Architecture](architecture.md)
- [Dependencies](dependencies.md)
- [Configuration](configuration.md)
- [Operations and processes](operations-processes.md)
- [Business rules](business-rules.md)
- [Service registration](service-registration.md)
- [API reference](api/index.md)

> **Note:** Statements marked with `*` were inferred from code structure, naming
> conventions, or contextual evidence where direct confirmation was not available
> in source artifacts. Statements marked with `**` could not be confirmed; treat
> as unknown until verified.

## Sources
- `src/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/Authorization/SecurityApiAuthorize.cs`
- `src/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/Authorization/SecurityAPIPolicy.cs`
- `src/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/Authorization/SecurityApiRequirement.cs`
- `src/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/Authorization/SecurityApiHandler.cs`
- `src/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/Clients/SecurityClient.cs`
- `src/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/Clients/SecurityClientException.cs`
- `src/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/Clients/OktaTokenClient.cs`
- `src/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/Extensions/AuthenticationServiceExtensions.cs`
- `src/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/Identity/BaseIdentityService.cs`
- `src/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/Identity/TokenIdentityService.cs`
- `src/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/Identity/WinIdentityService.cs`
- `src/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/Identity/IdentityServiceAccessor.cs`
- `src/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/Identity/MultiIdentityServiceAccessor.cs`
- `src/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/Interfaces/ISecurityClient.cs`
- `src/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/Interfaces/IAccessTokenClient.cs`
- `src/SAIF.NetCore.ServiceContracts/SAIF.NetCore.ServiceContracts/SAIF.NetCore.ServiceContracts/IIdentityService.cs`
- `src/SAIF.NetCore.NtlmApiAuth/src/SAIF.NetCore.NtlmApiAuth/Services/NtmlApiAuthorizationService.cs`
