npm package: @quandis/qbo4.security
Description: Provides web-based authentication controls and API endpoints for managing accounts and security-related features such as token generation, access keys, and IP address restrictions.
Latest version: 4.0.1-CI-20260312-212127

﻿# Security Management

Provides web-based authentication controls and API endpoints for managing accounts and security-related features such as token generation, access keys, and IP address restrictions.

## API Samples

**POST** `/security/account/token`

Use this method to obtain a JavaScript Web Token.

```csharp
using System.Net.Http.Json;

var http = new HttpClient
{
    BaseAddress = new Uri("https://your-api-host")
};

var tokenRequest = new TokenRequest
{
    AccessKey = "your-access-key",
    SecretKey = "your-secret-key"
};

var response = await http.PostAsJsonAsync("/security/account/token", tokenRequest);
response.EnsureSuccessStatusCode();

var token = await response.Content.ReadFromJsonAsync<TokenResponse>();

Console.WriteLine($"Access Token: {token?.AccessToken}");
Console.WriteLine($"Token Type: {token?.TokenType}");
Console.WriteLine($"Expires In (seconds): {token?.ExpiresInSeconds}");
```

```bash
curl -X POST "https://your-api-host/security/account/token" \
     -H "Content-Type: application/json" \
     -d '{
           "accessKey": "your-access-key",
           "secretKey": "your-secret-key"
         }'
```

## Web Controls

The following web controls are provided for authentication and security flows.


### Sign-In Control
`<qbo-login>` — Login + 2FA + SSO + License flow.
A Lit-based web component that implements a full authentication funnel:

- Username/password sign-in.
- Optional two-factor (SMS/Email/Authenticator) via `<qbo-2fa>`.
- Optional license acceptance gate.
- Password change/reset/invite confirmations via `<qbo-password>` / `<qbo-invite>`.
- Pluggable SSO (“OIDC”) buttons.
- Slot-based theming and header/footer overrides.


#### Quick start

```json
<script type="module" src="/path/to/qbo-login.js"></script>

<qbo-login
  pathbase="/auth/"                 <!-- every API call is relative to this -->
  allowedSSOLoginList="Google,Okta" <!-- restrict SSO buttons -->
  shouldfollowreturnurl="true"      <!-- follow ReturnUrl after sign-in -->
  enableauthenticator="true"        <!-- show authenticator option in 2FA -->
>
  <!-- Optional styling injected into the shadow DOM -->
  <style slot="login-styles">
    /* Your custom CSS */
  </style>

  <!-- Optional: replace the default header -->
  <div slot="login-form-header">
    <qbo-form-header heading="Welcome back" subheading="Sign in to continue"></qbo-form-header>
  </div>
</qbo-login>
```
By default, the component renders inside a shadow root. Set `lightdom` to true if you prefer light DOM.

#### Server endpoints (expected)

All endpoints are built from `pathbase` (e.g., /auth/):
- POST {base}signin – main login.
- Response (subset):.
```json
{
  "succeeded": true,
  "requiresTwoFactor": false,
  "licenseAcceptEndpoint": "",
  "legacyPasswordWeak": false,
  "ipValidationFailed": false,
  "changePasswordRequired": false,
  "isLockedOut": false,
  "isNotAllowed": false,
  "phoneRequired": false,
  "emailConfirmation": false,
  "returnUrl": "/",
  "twoFactorMethods": [
    { "methodType": "Email", "value": "masked@domain.com" },
    { "methodType": "Phone", "value": "+1 (*** ) ***-1234" },
    { "methodType": "Authenticator", "value": "enabled|disabled" }
  ],
  "exception": null
}
```
- `GET {base}oidc` – SSO providers.
    - Response: `[{ displayName, authenticationScheme, imagePath? }, ...]`.
- `GET {base}license` – fetch license content.
    - Response: `{ html?: string, text?: string, date: string }`.
- `POST {base}license` – accept license (expects 200 and body containing “accepted”)
- `GET {base}signout` – log out
Two-factor (SMS/Email/Auth) & phone add/change are handled inside <qbo-2fa> using additional endpoints (e.g., twofa/sms, phone/add, etc.).

#### Attributes / Properties

|Name|Type|Default|Description|
|-|-|-|-|
|`pathbase`|string|`undefined`|Base path for all API calls|
|`allowedSSOLoginList`|string|""|Comma-separated list of allowed SSO schemes (case-insensitive. If empty, no SSO buttons render.|
|`renderLogout`|boolean|false|If true, renders a Logout button|
|`lightdom`|boolean|false|If true, renders in light DOM|
|`enableauthenticator`|string|"true"|Enables offering the Authenticator method in 2FA. Use "false" to disable|
|`shouldfollowreturnurl`|string|"true"|if "true", navigates to ReturnUrl after success. If "false", navigates to current URL.|
|`licenseContent`|object|null|Optional preloaded license content; if omitted, component fetches it when needed.|

Internal state (read-only for consumers):
- loginState: `'default' | 'twoFactor' | 'lockedOut' | 'notAllowed' | 'license' | 'register' | 'changePasswordRequired' | 'passwordWeak' | 'reset' | 'resetEmail' | 'phoneRequired' | 'invite' | 'licenseAcceptEndpoint' | 'emailConfirmation' | 'phoneChange' | 'ipFailed' | 'error' | 'success'`

#### Slots
These slots let you customize headers, styles, parts of the flow. Anything not provided falls back to defaults.

|Slot name|Used in view|Purpose|
|-|-|-|
|`login-styles`|Login|Style elements in injected into the shadow root for the login view|
|`login-form-header`|Login|Replace the login header|
|`login-form`|Login|Replace the entire login form|
|`form-footer`|Login|Replace the login footer (buttons).|
|`divider`|Login|Replace the "or" divider|
|`oidc-buttons`|Login|Replace the SSO buttons container|
|`login-password-reset-form`|Login|Replace the "Forgot password?" link block|
|`login-register-form`|Login|Replace the "Register" link block|
|`mfa-form-header`|2FA/Email/Phone/Register|Header shown in `<qbo-2fa>` and registration MFA subflows|
|`mfa-styles`|2FA/Email/Phone/Register|Style elements injected into `<qbo-2fa>` shadow root.|
|`password-form-header`|Password update/reset/2FA|Header for password flows rendered via `<qbo-password>`|
|`password-styles`|Password update/reset/2FA|Styles injected into `<qbo-password>`|
|`password-change-form-header`|Password change required|Header specific to forced password change.|
|`invite-form-header`|Invite confirmation|Header for `<qbo-invite>`.|
|`invite-styles`|Invite confirmation|Styles injected into `<qbo-invite>`.|

For 2FA and password flows, headers/styles are forwarded to child components by cloning the slotted nodes.

#### Navigation and Return URL
- On initial load, the component reads `ReturnUrl` / `returnUrl` from the page query string and stores it internally.
- After successful auth:
    - If `shouldfollowreturnurl="true"` (default), navigate to `ReturnUrl` or `/`.
    - If `shouldfollowreturnurl="false"`, navigate to current location instead.

#### SSO ("OIDC") buttons
- On connect, the component calls `GET {base}odic`.
- You can restrict what to show via `allowedSSOLoginList="Google,Okta"`.
- Each provider may supply a custom `imagePath`. If omitted, the component builds a default icon URL using `getImageBasePath()` and `${displayName.toLowerCase()}-icon.svg`.

Clicking an SSO button redirects to 
```json
{base}oidc/login/{authenticationScheme}?ReturnUrl=<encoded>
```

#### Two-factor authentication (2FA)
When `POST /signin` returns `requiresTwoFactor:true`, the component enters the twoFactor state and renders `<qbo-2fa>` with:

- `email`, `phoneNumber` and (optionally) `authenticator` method population.
- `enableAuthenticator` forwarded so you can disable the authenticator option globally.
- The same `pathbase`, `shouldfollowreturnurl`, and `returnurl`.
If the backend returns `licenseAcceptEndpoint` after 2FA sign-in, `<qbo-2fa>` dispatches a license-required event. `<qbo-login>` listens for this and switches to the license view.

#### License gate
License can be triggered either:

- Directly after `POST /signin` (when `licenseAcceptEndpoint` is present) or
- Emitted by child flows via a `license-required` custom event (eg., after 2FA sign-in).

The component fetches license content with `GET {base}license`, then renders an accept view. Accepting POSTS to `{base}license` and navigates on success.

You can also preload content by setting the licenseContent property.

#### Password flows
- Weak legacy password → `passwordWeak` state → `<qbo-password isReset="true">`
- Change required → `changePasswordRequired` → `<qbo-password isPasswordChange="true">`
- Forgot password? → `resetEmail` → `<qbo-password isReset="true">`
- Direct reset link → `rest` state (`passwordReset=true&userid=...&token=...` present)

All header/styles slots for password flows are forwarded to `<qbo-password>`

#### Invite confirmation
If the query string includes `?registerConfirm=true&userid=...&token=...`, the component enters the invite state and renders `<qbo-invite>`, passing `userId` / `token`. The invite component performs confirmation, then redirects as needed.

#### Error states
- `lockedOut` / `notAllowed` / `ipFailed` show "contact support" with a link back to login.
- Any non-OK responses with `exception` => `error` state with an error message.
- Inline status messages are rendered via `renderDismissibleStatus`.

#### Styling
- Base CSS: `qbocss` + `securityCss`
- Provide `<style slot="login-styles">` to inject additional styles into the login shadow root.
- Provide `<style slot="mfa-styles">` etc.. for subflows.

If you must style from the outside, set `lightdom="true"`.

#### Events listened and propagated
- Listened: license-required (bubbles/composed). When received, the component fetches and shows the license agreement.
- Propagated: Subcomponents (2FA/password/invite) handle their own events internally and redirect according to the same naviation rules.

#### Examples
1) Disable authenticator method and restrict to Okta SSO
```json
<qbo-login
  pathbase="/auth/"
  enableauthenticator="false"
  allowedSSOLoginList="Okta"
></qbo-login>
```
2) Light DOM (for global CSS) with custom footer
```json
<qbo-login lightdom pathbase="/auth/">
  <div slot="form-footer">
    <div class="actions">
      <button type="submit" class="qbo-base-button">Sign in</button>
      <a href="/help" class="qbo-link">Need help?</a>
    </div>
  </div>
</qbo-login>
```
3) Supply custom MFA and password styles/headers
```json
<qbo-login pathbase="/auth/">
  <style slot="mfa-styles">
    .qbo-mfa-form { max-width: 480px; }
  </style>
  <div slot="mfa-form-header">
    <qbo-form-header heading="Two-factor" subheading="Enter the code to continue"></qbo-form-header>
  </div>

  <style slot="password-styles">
    .qbo-password-form { max-width: 480px; }
  </style>
  <div slot="password-form-header">
    <qbo-form-header heading="Update password" subheading="Please choose a stronger password"></qbo-form-header>
  </div>
</qbo-login>
```
### Access Key Control

This is where the access key control documentation would go.

### IP Address Control

This is where the IP address control documentation would go.