Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 21 additions & 42 deletions src/Umbraco.Web.UI.Login/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
TypeScript/Lit login SPA for Umbraco CMS backoffice authentication. Provides the `<umb-auth>` web component used in the login page, supporting local login, MFA, password reset, and user invitation flows.

**Project Type**: TypeScript Library (Vite)
**Runtime**: Node.js >= 24.13, npm >= 11
**Runtime**: Node.js (see `.nvmrc`), npm >= 10.9
**Output**: ES Module library → `../Umbraco.Cms.StaticAssets/wwwroot/umbraco/login/`
**Dependencies**: Lit, Vite, MSW (Login does **not** declare an npm dep on `@umbraco-cms/backoffice` — see below)

Expand Down Expand Up @@ -47,18 +47,13 @@ This project builds the login single-page application:
1. **Web Component** - `<umb-auth>` custom element for authentication
2. **Authentication Flows** - Login, MFA, password reset, user invitation
3. **Localization** - Multi-language support (en, de, da, nb, nl, sv)
4. **API Client** - Generated from OpenAPI specification
4. **API Integration** - Direct `fetch()` for login/MFA; `SecurityService`/`UserService` from `@umbraco-cms/backoffice/external/backend-api` for other operations

### Folder Structure

```
Umbraco.Web.UI.Login/
├── src/
│ ├── api/ # Generated API client
│ │ ├── client/ # HTTP client utilities
│ │ ├── core/ # Serializers, types
│ │ ├── sdk.gen.ts # Generated SDK
│ │ └── types.gen.ts # Generated types
│ ├── components/
│ │ ├── layouts/ # Layout components
│ │ │ ├── auth-layout.element.ts
Expand All @@ -73,8 +68,8 @@ Umbraco.Web.UI.Login/
│ │ │ └── invite.page.element.ts
│ │ └── back-to-login-button.element.ts
│ ├── contexts/
│ │ ├── auth.context.ts # Authentication state (86 lines)
│ │ └── auth.repository.ts # API calls (231 lines)
│ │ ├── auth.context.ts # Authentication state
│ │ └── auth.repository.ts # API calls
│ ├── controllers/
│ │ └── slim-backoffice-initializer.ts # Minimal backoffice bootstrap
│ ├── localization/
Expand All @@ -86,19 +81,18 @@ Umbraco.Web.UI.Login/
│ │ │ └── backoffice.handlers.ts
│ │ └── data/login.data.ts
│ ├── utils/
│ │ ├── is-problem-details.function.ts
│ │ └── load-custom-view.function.ts
│ ├── auth.element.ts # Main <umb-auth> component (404 lines)
│ ├── auth.element.ts # Main <umb-auth> component
│ ├── types.ts # Type definitions
│ ├── manifests.ts # Extension manifests
│ └── umbraco-package.ts # Package definition
├── public/
│ └── favicon.svg
├── index.html # Development entry point
├── package.json # npm configuration (29 lines)
├── tsconfig.json # TypeScript config (25 lines)
├── vite.config.ts # Vite build config (20 lines)
├── .nvmrc # Node version (22)
├── package.json # npm configuration
├── tsconfig.json # TypeScript config
├── vite.config.ts # Vite build config
├── .nvmrc # Node version pin
└── .prettierrc.json # Prettier config
```

Expand Down Expand Up @@ -139,24 +133,15 @@ npm run watch
npm run preview
```

### API Generation

```bash
# Regenerate API client from OpenAPI spec
npm run generate:server-api
```

Uses `@hey-api/openapi-ts` to generate TypeScript client from the Management API OpenAPI specification.

---

## 3. Key Components

### UmbAuthElement (src/auth.element.ts)

Main `<umb-auth>` web component (404 lines).
Main `<umb-auth>` web component.

**Attributes** (lines 172-204):
**Attributes**:
| Attribute | Type | Description |
|-----------|------|-------------|
| `disable-local-login` | boolean | Disables local login, external only |
Expand All @@ -168,20 +153,20 @@ Main `<umb-auth>` web component (404 lines).
| `allow-user-invite` | boolean | Enable user invitation flow |
| `return-url` | string | Redirect URL after login |

**Authentication Flows** (lines 379-396):
**Authentication Flows**:

- Default: Login page with username/password
- `flow=mfa`: Multi-factor authentication
- `flow=reset`: Request password reset
- `flow=reset-password`: Set new password
- `flow=invite-user`: User invitation acceptance

**Form Workaround** (lines 274-334):
**Form Workaround**:
Creates login form in light DOM (not shadow DOM) to support Chrome autofill/autocomplete, which doesn't work properly with shadow DOM inputs.

### UmbAuthContext (src/contexts/auth.context.ts)

Authentication state and API methods (86 lines):
Authentication state and API methods:

- `login(data)` - Authenticate user
- `resetPassword(username)` - Request password reset
Expand All @@ -191,7 +176,7 @@ Authentication state and API methods (86 lines):
- `newInvitedUserPassword(...)` - Set invited user password
- `validateMfaCode(code, provider)` - MFA validation

**Return Path Security** (lines 37-54): Validates return URL to prevent open redirect attacks - only allows same-origin URLs.
**Return Path Security**: Validates return URL to prevent open redirect attacks - only allows same-origin URLs.

### Localization

Expand All @@ -218,23 +203,22 @@ Development uses MSW for API mocking. Run `npm run dev` to start with mocks enab

### Shadow DOM Limitation

Chrome doesn't support autofill in shadow DOM inputs. The login form is created in light DOM via `#initializeForm()` (lines 274-334) and inserted with `insertAdjacentElement()`. See Chromium intent-to-ship discussion linked in code.
Chrome doesn't support autofill in shadow DOM inputs. The login form is created in light DOM via `#initializeForm()` and inserted with `insertAdjacentElement()`. See Chromium intent-to-ship discussion linked in code.

### Slim Backoffice Controller

`UmbSlimBackofficeController` provides minimal backoffice utilities (extension registry, localization, context API) without loading the full app.

### Localization Wait Pattern (lines 242-265)
### Localization Wait Pattern

Form waits for localization availability before rendering. Retries 40 times with 50ms interval (2 second max wait).

### External Dependencies

- `@umbraco-cms/backoffice` ^16.2.0 - Umbraco UI components, Lit element base
- `vite` ^7.2.0 - Build tooling
- `typescript` ^5.9.3 - Type checking
- `msw` ^2.11.3 - API mocking
- `@hey-api/openapi-ts` ^0.85.0 - API client generation
- `@umbraco-cms/backoffice` - Umbraco UI components, Lit element base, backoffice API services
- `vite` - Build tooling
- `typescript` - Type checking
- `msw` - API mocking (dev only)

### Known Technical Debt

Expand All @@ -246,8 +230,6 @@ Form waits for localization availability before rendering. Retries 40 times with
- `new-password-layout.element.ts:221`
- `reset-password.page.element.ts:110`

2. **API Client Error Types** (`api/client/client.gen.ts:207`): Error handling and types need improvement

### TypeScript Configuration

Key settings in `tsconfig.json`:
Expand All @@ -269,9 +251,6 @@ Key settings in `tsconfig.json`:
npm run dev # Start dev server
npm run build # Build to StaticAssets
npm run watch # Watch mode

# API
npm run generate:server-api # Regenerate API client
```

### Key Files
Expand Down
33 changes: 0 additions & 33 deletions src/Umbraco.Web.UI.Login/openapi-ts.config.ts

This file was deleted.

Loading
Loading