# Active sessions

Compose sessions with the auth service and your own interface.

Import: @slices.sh/auth/headless

Public parts: 13

## Installation

### 1. Install the service registry

services/index.ts, which `import "@/services"` loads. A provider setup writes the same file; skip this if your app has one.

```bash
npx shadcn@latest add "https://slices.sh/r/services.json"
```

### 2. Install the headless library

```bash
npm install @slices.sh/auth@^0.1.10
```

### 3. Install the service

Install the provider configuration via shadcn or the slices CLI. Skip this step if your app already has the service configured. Provider commands and provisioning: https://slices.sh/docs/services/auth.md

## Anatomy

### Composition

```text
User.Root
  Sessions.Root
    Sessions.Available
      Sessions.Item
        Sessions.Current for the first device
          Sessions.ActionTrigger
        Sessions.ActionDialog
          Sessions.Confirm
          Sessions.Cancel
        Sessions.ActionError
    Sessions.Loading
    Sessions.Empty
    Sessions.Error
      Sessions.Retry
```

## Minimal composition

```tsx
"use client"

import "@/services"
import { Sessions } from "@slices.sh/auth/headless"

export function Example() {
  return (
    <Sessions.Root>
      <Sessions.Item>
        <Sessions.Current>This device</Sessions.Current>
        <Sessions.ActionTrigger>Sign out device</Sessions.ActionTrigger>
        <Sessions.ActionDialog>
          <Sessions.Confirm>Confirm</Sessions.Confirm>
          <Sessions.Cancel>Cancel</Sessions.Cancel>
        </Sessions.ActionDialog>
      </Sessions.Item>
      <Sessions.Empty>No sessions.</Sessions.Empty>
      <Sessions.Error />
    </Sessions.Root>
  )
}

```

Requires an authenticated account. Organization controls also require organizations and the appropriate role.

## Complete API reference

### Sessions.Root

scope

Available gates the section where the backend lists sessions.

Import: @slices.sh/auth/headless

Capability: sessions

```tsx
RootProps & AuthRootProps
```

Alternate import: Sessions.Root from @slices.sh/auth/headless/sessions

Source: @slices.sh/auth/src/headless/sessions/root.tsx

### Sessions.Available

gate

Available gates the section where the backend lists sessions.

Import: @slices.sh/auth/headless

Capability: sessions

```tsx
GateProps
```

Alternate import: Sessions.Available from @slices.sh/auth/headless/sessions

Source: @slices.sh/auth/src/headless/sessions/available.tsx

### Sessions.Loading

gate

Loading, Empty, Error (<p role="alert"> with { message }) and Retry for the read.

Import: @slices.sh/auth/headless

```tsx
GateProps
```

Alternate import: Sessions.Loading from @slices.sh/auth/headless/sessions

Source: @slices.sh/auth/src/headless/sessions/loading.tsx

### Sessions.Empty

gate

Loading, Empty, Error (<p role="alert"> with { message }) and Retry for the read.

Import: @slices.sh/auth/headless

```tsx
GateProps
```

Alternate import: Sessions.Empty from @slices.sh/auth/headless/sessions

Source: @slices.sh/auth/src/headless/sessions/empty.tsx

### Sessions.Error

content · Element: p

Loading, Empty, Error (<p role="alert"> with { message }) and Retry for the read.

Import: @slices.sh/auth/headless

```tsx
PartProps<"p", { message: string }>
```

Alternate import: Sessions.Error from @slices.sh/auth/headless/sessions

Source: @slices.sh/auth/src/headless/sessions/error.tsx

### Sessions.Retry

action · Element: button

Loading, Empty, Error (<p role="alert"> with { message }) and Retry for the read.

Import: @slices.sh/auth/headless

```tsx
PartProps<"button">
```

Alternate import: Sessions.Retry from @slices.sh/auth/headless/sessions

Source: @slices.sh/auth/src/headless/sessions/retry.tsx

### Sessions.Item

content · Element: li

Item repeats once per session with { browser, os, createdAt, ipAddress }; unknown values are null. Current opens inside this device's row.

Import: @slices.sh/auth/headless

Sessions.Item provides its own scope.

```tsx
ItemProps

type ItemProps = PartProps<
  "li",
  {
    browser: string | null
    os: string | null
    createdAt: Date
    ipAddress: string | null
    /** The address is this machine's (loopback) or none (unspecified), as on a dev server. */
    local: boolean
  }
>
```

Alternate import: Sessions.Item from @slices.sh/auth/headless/sessions

Source: @slices.sh/auth/src/headless/sessions/item.tsx

### Sessions.Current

gate

Item repeats once per session with { browser, os, createdAt, ipAddress }; unknown values are null. Current opens inside this device's row.

Import: @slices.sh/auth/headless

Sessions.Current requires a device row.

```tsx
GateProps
```

Alternate import: Sessions.Current from @slices.sh/auth/headless/sessions

Source: @slices.sh/auth/src/headless/sessions/current.tsx

### Sessions.ActionDialog

content

ActionDialog maps the armed state onto render={<AlertDialog />}. ActionTrigger arms it, with { pending, retryAfter }. Confirm ends the session, or every other one outside a row. Cancel disarms. ActionError gets { message }.

Import: @slices.sh/auth/headless

Sessions.ActionDialog requires Sessions.Root.

```tsx
PartProps<null>
```

Alternate import: Sessions.ActionDialog from @slices.sh/auth/headless/sessions

Source: @slices.sh/auth/src/headless/sessions/action-dialog.tsx

### Sessions.ActionTrigger

action · Element: button

ActionDialog maps the armed state onto render={<AlertDialog />}. ActionTrigger arms it, with { pending, retryAfter }. Confirm ends the session, or every other one outside a row. Cancel disarms. ActionError gets { message }.

Import: @slices.sh/auth/headless

Sessions.ActionTrigger requires Sessions.Root.

```tsx
PartProps<"button", { pending: boolean; retryAfter: number }>
```

Alternate import: Sessions.ActionTrigger from @slices.sh/auth/headless/sessions

Source: @slices.sh/auth/src/headless/sessions/action-trigger.tsx

### Sessions.Cancel

action · Element: button

ActionDialog maps the armed state onto render={<AlertDialog />}. ActionTrigger arms it, with { pending, retryAfter }. Confirm ends the session, or every other one outside a row. Cancel disarms. ActionError gets { message }.

Import: @slices.sh/auth/headless

Sessions.Cancel requires Sessions.Root.

```tsx
PartProps<"button">
```

Alternate import: Sessions.Cancel from @slices.sh/auth/headless/sessions

Source: @slices.sh/auth/src/headless/sessions/cancel.tsx

### Sessions.Confirm

action · Element: button

ActionDialog maps the armed state onto render={<AlertDialog />}. ActionTrigger arms it, with { pending, retryAfter }. Confirm ends the session, or every other one outside a row. Cancel disarms. ActionError gets { message }.

Import: @slices.sh/auth/headless

Sessions.Confirm requires Sessions.Root.

```tsx
PartProps<"button", { pending: boolean; retryAfter: number }>
```

Alternate import: Sessions.Confirm from @slices.sh/auth/headless/sessions

Source: @slices.sh/auth/src/headless/sessions/confirm.tsx

### Sessions.ActionError

content · Element: p

ActionDialog maps the armed state onto render={<AlertDialog />}. ActionTrigger arms it, with { pending, retryAfter }. Confirm ends the session, or every other one outside a row. Cancel disarms. ActionError gets { message }.

Import: @slices.sh/auth/headless

Sessions.ActionError requires Sessions.Root.

```tsx
PartProps<"p", { message: string }>
```

Alternate import: Sessions.ActionError from @slices.sh/auth/headless/sessions

Source: @slices.sh/auth/src/headless/sessions/action-error.tsx

### User.Root

scope

Says which auth the User parts below read, and whether they may do without it. The parts need
no root: left out, they read the nearest auth root's config, or "default", and render nothing
without auth. `<User.Root enabled="optional">` is for the one who wants that said in the code.

Import: @slices.sh/auth/headless

```tsx
RootProps & AuthRootProps
```

Alternate import: User.Root from @slices.sh/auth/headless/user

Alternate import: User.Root from @slices.sh/auth/headless/passkeys

Alternate import: User.Root from @slices.sh/auth/headless/two-factor

Source: @slices.sh/auth/src/headless/user/root.tsx
