# How the Logto Account Center Works: Architecture, API, and Front-End Integration

> Explore the Logto Account Center architecture, APIs, and front-end integration. Learn how it empowers users to manage profiles, passwords, and linked identities.

- Repository: [Logto/logto](https://github.com/logto-io/logto)
- Tags: architecture
- Published: 2026-07-05

---

**The Logto Account Center is a self-service hub that combines database-persisted configuration, cached middleware injection, management API endpoints, and Lit-based web components to let users manage their profiles, passwords, and linked identities.**

The **account center** in the `logto-io/logto` repository provides end users with a centralized interface to manage account settings, including profile data, passwords, and social identities. Its implementation spans PostgreSQL schemas, cached query layers, Koa middleware, and framework-agnostic web components. This article breaks down how these layers interact to deliver a seamless self-service experience.

## Database Schema and Configuration Storage

The account center configuration is stored in the `account_centers` table, defined in [`packages/schemas/tables/account_centers.sql`](https://github.com/logto-io/logto/blob/main/packages/schemas/tables/account_centers.sql). The corresponding seed file at [`packages/schemas/src/seeds/account-center.ts`](https://github.com/logto-io/logto/blob/main/packages/schemas/src/seeds/account-center.ts) populates the default row.

The table stores critical fields including `enabled`, `fields`, `customCss`, `profileFields`, and an optional `deleteAccountUrl`. Only one record exists in practice—the row with `id = 'default'`—which serves as the global configuration for the entire tenant.

## Query Layer and Caching Strategy

All database interactions flow through the `AccountCenterQueries` class in [`packages/core/src/queries/account-center.ts`](https://github.com/logto-io/logto/blob/main/packages/core/src/queries/account-center.ts). This class extends `SchemaQueries` and implements aggressive caching via `WellKnownCache` ([`packages/core/src/caches/well-known.ts`](https://github.com/logto-io/logto/blob/main/packages/core/src/caches/well-known.ts)).

The query layer exposes two primary methods:

```ts
// packages/core/src/queries/account-center.ts
export class AccountCenterQueries extends SchemaQueries<...> {
  public readonly findDefaultAccountCenter = this.wellKnownCache.memoize(
    async () => this.findById('default'),   // ← always fetch the row with id = 'default'
    ['account-center']
  );

  public readonly updateDefaultAccountCenter = this.wellKnownCache.mutate(
    async (accountCenter) => this.updateById('default', accountCenter, 'replace'),
    ['account-center']
  );
}

```

**findDefaultAccountCenter** retrieves the configuration with memoization, while **updateDefaultAccountCenter** mutates the cache atomically when settings change. This ensures that high-traffic routes read from memory rather than hitting PostgreSQL repeatedly.

## Middleware Injection

Before any protected route accesses account center data, the `koaAccountCenter` middleware ([`packages/core/src/routes/account/middlewares/koa-account-center.ts`](https://github.com/logto-io/logto/blob/main/packages/core/src/routes/account/middlewares/koa-account-center.ts)) validates and injects the configuration into the Koa context.

```ts
// packages/core/src/routes/account/middlewares/koa-account-center.ts
export default function koaAccountCenter<StateT, ContextT, ResponseT>({ accountCenters }: Queries) {
  return async (ctx, next) => {
    const accountCenter = await findDefaultAccountCenter(); // ← query from the DB
    assertThat(accountCenter.enabled, 'account_center.not_enabled');
    ctx.accountCenter = accountCenter;                     // ← made available downstream
    return next();
  };
}

```

This middleware guarantees that downstream handlers can access `ctx.accountCenter` without additional database queries, and it enforces that the feature is enabled before processing requests.

## Management API and Well-Known Endpoints

The management API exposes the account center under `/account-center` in [`packages/core/src/routes/account-center/index.ts`](https://github.com/logto-io/logto/blob/main/packages/core/src/routes/account-center/index.ts). The router handles both reads and writes:

```ts
// packages/core/src/routes/account-center/index.ts
router.get('/account-center', koaGuard({ response: AccountCenters.guard }), async (ctx, next) => {
  ctx.body = await findDefaultAccountCenter();   // read
  return next();
});

router.patch('/account-center', koaGuard({ body: z.object({ … }), response: AccountCenters.guard }), async (ctx, next) => {
  const { enabled, fields, webauthnRelatedOrigins, deleteAccountUrl, customCss, profileFields } = ctx.guard.body;
  // normalise fields, deduplicate origins, etc.
  const updated = await updateDefaultAccountCenter({ … });
  ctx.body = updated;                             // write
  return next();
});

```

For unauthenticated access, the configuration is also exposed via the well-known endpoint `GET /.well-known/account-center` in [`packages/core/src/routes/well-known/index.ts`](https://github.com/logto-io/logto/blob/main/packages/core/src/routes/well-known/index.ts). This allows front-end applications to fetch UI settings before the user authenticates.

## Front-End Integration

### Fetching Configuration

Front-end applications retrieve settings through the helper in [`packages/account/src/apis/account-center.ts`](https://github.com/logto-io/logto/blob/main/packages/account/src/apis/account-center.ts):

```ts
// packages/account/src/apis/account-center.ts
export const getAccountCenterSettings = async (): Promise<AccountCenter> =>
  ky.get('/api/.well-known/account-center').json<AccountCenter>();

```

This function uses `ky` to fetch the well-known endpoint, making it available to the Lit components without requiring management API tokens.

### The Account Center Component

The core UI element is the `LogtoAccountCenter` Lit component in [`packages/elements/src/account/elements/logto-account-center.ts`](https://github.com/logto-io/logto/blob/main/packages/elements/src/account/elements/logto-account-center.ts). It consumes the `logtoAccountContext` from [`packages/elements/src/account/providers/logto-account-provider.ts`](https://github.com/logto-io/logto/blob/main/packages/elements/src/account/providers/logto-account-provider.ts) to render profile sections dynamically.

```ts
// packages/elements/src/account/elements/logto-account-center.ts
@customElement('logto-account-center')
export class LogtoAccountCenter extends LitElement {
  @consume({ context: logtoAccountContext, subscribe: true })
  private readonly accountContext?: LogtoAccountContextType;

  render() {
    if (!this.accountContext) return html`<span>Unable to retrieve account context.</span>`;
    const { username, primaryEmail, primaryPhone, hasPassword, identities } = this.accountContext.userProfile;
    return html`
      ${username !== undefined && html`<logto-username></logto-username>`}
      ${primaryEmail !== undefined && html`<logto-user-email></logto-user-email>`}
      ${primaryPhone !== undefined && html`<logto-user-phone></logto-user-phone>`}
      ${hasPassword !== undefined && html`<logto-user-password></logto-user-password>`}
      ${identities !== undefined && Object.entries(identities).map(
        ([target]) => html`<logto-social-identity target=${target}></logto-social-identity>`
      )}
    `;
  }
}

```

The component conditionally renders sub-components based on the available user profile data, ensuring only relevant sections (username, email, phone, password, social identities) appear in the UI.

### Routing and Session Management

Since the account center operates under a dedicated base path (e.g., `/account`), the utility module [`packages/account/src/utils/account-center-route.ts`](https://github.com/logto-io/logto/blob/main/packages/account/src/utils/account-center-route.ts) handles redirect logic and state preservation.

Key functions include:

- **accountCenterBasePath** – Defines the base URL segment (e.g., `/account`).
- **handleAccountCenterRoute()** – Extracts `redirect`, `show_success`, and `ui_locales` query parameters, storing them in `sessionStorage` ([`packages/account/src/utils/session-storage.ts`](https://github.com/logto-io/logto/blob/main/packages/account/src/utils/session-storage.ts)) for retrieval after authentication redirects.

This ensures users return to their intended account page after signing in, with their preferred locale intact.

## End-to-End Flow

When a user navigates to the account center:

1. The **Lit component** mounts and requests the configuration via `getAccountCenterSettings()`.
2. The **well-known endpoint** returns the cached configuration from the database.
3. **Middleware** (`koaAccountCenter`) validates that the center is enabled for any authenticated API calls.
4. The component renders **profile sections** based on the configuration and current user data.
5. When settings change, the front-end calls `PATCH /account-center`, triggering `updateDefaultAccountCenter` to persist changes and invalidate the cache.

## Code Examples

### Enabling a Custom Field

To enable the account center and add a custom field from your application:

```ts
import ky from 'ky';

// Enable the account‑center and add the “profile picture” field
await ky.patch('/api/account-center', {
  json: {
    enabled: true,
    fields: {
      // field name → control definition (see @logto/schemas for shape)
      profilePicture: { displayName: 'Profile Picture', isOptional: true }
    }
  }
}).json();

```

### Handling Post-Update Redirects

After a successful profile update, restore the user's original destination:

```ts
import { getPendingReturn, clearPendingReturn } from './account-center-route.js';

export const onProfileSaved = async () => {
  const returnUrl = getPendingReturn();
  clearPendingReturn();               // one‑time use
  if (returnUrl) {
    window.location.assign(returnUrl);
  }
};

```

### Integrating the Component

Use the account center component in a React or Vue application:

```tsx
// Inside a Vite‑based Experience page
import '@logto/elements/account'; // registers <logto-account-center>

export default function AccountPage() {
  return (
    <section>
      <h1>My Account</h1>
      <logto-account-center></logto-account-center>
    </section>
  );
}

```

## Summary

- **Database Layer**: Configuration resides in the `account_centers` table with a single default row, seeded via [`packages/schemas/src/seeds/account-center.ts`](https://github.com/logto-io/logto/blob/main/packages/schemas/src/seeds/account-center.ts).
- **Caching**: `AccountCenterQueries` leverages `WellKnownCache` to memoize reads and atomically mutate writes, minimizing database load.
- **Middleware**: `koaAccountCenter` injects the configuration into the Koa context and enforces the enabled state.
- **API Surface**: Management routes at `/account-center` support CRUD operations, while `/.well-known/account-center` provides public read access.
- **Front-End**: A Lit-based component in [`packages/elements/src/account/elements/logto-account-center.ts`](https://github.com/logto-io/logto/blob/main/packages/elements/src/account/elements/logto-account-center.ts) renders the UI, consuming context from `logtoAccountProvider` and using utilities in [`packages/account/src/utils/account-center-route.ts`](https://github.com/logto-io/logto/blob/main/packages/account/src/utils/account-center-route.ts) for redirect handling.

## Frequently Asked Questions

### How is the account center configuration cached?

The `AccountCenterQueries` class in [`packages/core/src/queries/account-center.ts`](https://github.com/logto-io/logto/blob/main/packages/core/src/queries/account-center.ts) uses `WellKnownCache` to memoize the `findDefaultAccountCenter` method. When configuration updates via `updateDefaultAccountCenter`, the cache mutates atomically, ensuring subsequent reads return fresh data without querying PostgreSQL.

### What happens if the account center is disabled?

The `koaAccountCenter` middleware in [`packages/core/src/routes/account/middlewares/koa-account-center.ts`](https://github.com/logto-io/logto/blob/main/packages/core/src/routes/account/middlewares/koa-account-center.ts) asserts that `accountCenter.enabled` is true before attaching the configuration to the context. If disabled, it throws an `account_center.not_enabled` error, preventing downstream handlers from processing account-related requests.

### How do front-end applications access account center settings without authentication?

Front-end code calls the well-known endpoint `GET /.well-known/account-center` defined in [`packages/core/src/routes/well-known/index.ts`](https://github.com/logto-io/logto/blob/main/packages/core/src/routes/well-known/index.ts). This endpoint returns the account center configuration without requiring a management API token, allowing the UI to render appropriate fields before the user authenticates.

### Can I customize which fields appear in the account center?

Yes. Administrators can `PATCH /api/account-center` with a `fields` object defining which profile sections to display. The `LogtoAccountCenter` component in [`packages/elements/src/account/elements/logto-account-center.ts`](https://github.com/logto-io/logto/blob/main/packages/elements/src/account/elements/logto-account-center.ts) dynamically renders only the components corresponding to the enabled fields and available user data, such as `logto-user-email` or `logto-social-identity`.