Claude 387e10b2fb fix(auth/middleware): recognize chunked session cookies
NextAuth v5 chunks the session cookie when the JWT payload exceeds
~4KB (we hit this easily: keycloakId + tenantId + display names +
roles + accessToken JWT + idToken). When chunked, the bare
'authjs.session-token' cookie is removed in favour of
'authjs.session-token.0', '.1', etc. Looking up only the bare name
returned undefined and the middleware redirected freshly-logged-in
users back to /api/auth/signin in a loop.

Match presence-only on any cookie whose name starts with either
canonical prefix. Server-side NextAuth still validates the token on
every RSC render — this check only gates the redirect.

Repro: gscCRM/v2.3.3 with the proxy fix in place. Keycloak auth
completes, /api/auth/callback/keycloak 302s, but every subsequent
request to / 307s straight back to signin because the middleware
doesn't see the now-chunked cookie.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 11:46:01 +02:00

@gsc/web-kit

App skeleton for GSC Next.js frontends. Curates @limitless/ui primitives behind a pre-configured layout + auth + data/forms/feedback/navigation stack so apps just write their domain pages.

See the implementation plan in the parent repo for the full module map. This is a file: dep consumed by every GSC frontend.

Install (in a consumer app)

// package.json
{
  "dependencies": {
    "@gsc/web-kit": "file:../../../templates/gsc-web-kit"
  }
}

Layered architecture

your app
  └── @gsc/web-kit         ← this package (layout, auth, data, forms…)
        └── @limitless/ui   ← Bootstrap-flavoured primitives
              └── bootstrap

Sub-exports

import "@gsc/web-kit/css";              // CSS bundle (layout-3 + JetBrains Mono)

// Chrome
import { AppLayout } from "@gsc/web-kit/layout";
import { useShell } from "@gsc/web-kit/shell";
import { fetchShellConfig } from "@gsc/web-kit/shell/server";

// Auth (NextAuth v5 + Keycloak)
import { createAuth } from "@gsc/web-kit/auth/server";
import { createAuthMiddleware } from "@gsc/web-kit/auth/middleware";
import { signInRedirect } from "@gsc/web-kit/auth";

// Building blocks — curated re-exports from @limitless/ui
import {
  Table, DataTable, Pagination, TreeView, Timeline,
  Calendar, Gallery, Sortable, ListGroup,
  StatWidget, ProgressWidget, ChartWidget, ContentWidget,
} from "@gsc/web-kit/data";

import {
  FormGroup, FormControl, FormCheck, Select, InputGroup,
  SelectSingle, MultiSelect, TagsSelect, AsyncSelect,
  DatePicker, ColorPicker, TagInput, FileUpload,
  Slider, Rating, DualListBox, ImageCropper, Wizard, Stepper,
  // validation
  useValidation, useFieldValidation, required, email, password,
  noInjection, europeanAddress, /* …etc */
} from "@gsc/web-kit/forms";

import {
  Alert, Toast, Notification, Modal, Offcanvas,
  Popover, Tooltip, SweetAlert, Spinner,
  Progress, ProgressStacked, IdleTimeout, FAB,
} from "@gsc/web-kit/feedback";

import {
  Breadcrumbs, Nav, Tabs, Pills, Dropdown, ContextMenu,
  Scrollspy, PageHeader, Accordion, Collapse, Carousel,
  Embed, SyntaxHighlighter, Card, Badge, Button, Media,
} from "@gsc/web-kit/navigation";

import { useDisclosure } from "@gsc/web-kit/utils";

The /api sub-export is reserved for a future HTTP client helper; it currently re-exports nothing.

Phases

Phase Scope Status
1 Package scaffold + CSS bundle + sub-export stubs done
2 layout · auth · shell — usable end-to-end with shell-api done
3 data · forms — curated re-exports from limitless + validation done (v0.3.0)
4 feedback · navigation · utils — curated re-exports from limitless done (v0.3.0)
4a api · HTTP client helper (Bearer injection, 401 → signInRedirect) planned
5 Roll out to gscCRM / gscChronos / gscAdmin / gscPortal planned

Notes

  • AppLayout is a thin wrapper around <AppShell> from @limitless/ui — they share the ShellConfig DTO, so the kit owns the consumer-facing surface without duplicating chrome code.
  • All form, data, feedback, and navigation modules are curated re-exports: apps should never need to reach into @limitless/ui directly.
  • The Widget family in /data is intentionally narrow (StatWidget, ProgressWidget, ChartWidget, ContentWidget) — the installed limitless dist has a duplicate Widget file/folder collision, so only names exported by both are passed through.
Description
App skeleton for GSC Next.js frontends. Layout, auth, data, forms, feedback, navigation on top of @limitless/ui.
Readme 454 KiB
Languages
TypeScript 92%
CSS 5.4%
JavaScript 2.6%