Skip to content

dogfood: auth() returns a loosely-typed session (user is Record<string, unknown>) #451

Description

@vivek7405

Problem

auth() returns a session whose user is typed as Record<string, unknown>. Custom fields set in the session callback — e.g. session.user.id, session.user.username — therefore have type unknown, so reading them requires a cast at every call site:

const session = await auth();
const userId = Number((session.user as { id?: number }).id); // forced cast

An AI writing route handlers/pages has to guess the field names and cast; TypeScript won't catch a typo (session.user.usrname). The real shape is already defined imperatively in the session/jwt callbacks (crisp does session.user.id = token.uid), but that shape isn't reflected back into auth()'s return type. This came up at nearly every gated route in the crisp rewrite.

Design / approach

Let an app declare its session/user shape and have auth() return it typed. Options (either, or both):

  • Module augmentation (NextAuth/Auth.js-style): declare module '@webjsdev/server' { interface Session { user: { id: number; username: string; ... } } }, which auth()'s return type picks up.
  • Generic: createAuth<TUser>({...}) whose auth() returns { user: TUser } | null.

Document the pattern in the auth recipe so agents use it by default.

Acceptance criteria

  • An app can declare its session-user shape so auth() returns it typed (no cast for session.user.id).
  • A wrong/misspelled field on session.user is a TypeScript error.
  • The auth doc shows the augmentation/generic pattern.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Type

No type

Projects

  • Status
    Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions