Describe the bug
TypeScript emits TS2883 (and on some configurations, the related TS2742) on consumer code that infers return types from withAuth() or refreshSession():
error TS2883: The inferred type of 'requireAuth' cannot be named without a reference to 'User' from
'@workos-inc/authkit-nextjs/node_modules/@workos-inc/node'. This is likely not portable.
A type annotation is necessary.
The error reproduces whenever the consumer's resolved version of @workos-inc/node differs from the version that satisfies authkit-nextjs's transitive ^9.0.0 range. Package managers then install a duplicate nested copy under node_modules/@workos-inc/authkit-nextjs/node_modules/@workos-inc/node/, and TypeScript can no longer write a portable declaration for any inferred type that surfaces User (or OauthTokens, AuthenticationResponse) through the public API.
To Reproduce
-
In a Next.js project, install @workos-inc/authkit-nextjs@^4.0.1 and pin @workos-inc/node directly to a version that doesn't match ^9.0.0's currently-resolved point version, e.g. 9.2.0 while authkit-nextjs's transitive resolution is still at 9.1.1. With Yarn 4 + node-modules linker this is what dependabot[bot] produces every time it bumps the direct pin.
-
Write any function whose return type is inferred from withAuth(). A minimal repro:
// lib/auth/session.ts
import { withAuth, getSignInUrl } from "@workos-inc/authkit-nextjs"
import { redirect } from "next/navigation"
export async function requireAuth() {
const session = await withAuth()
if (!session.user) {
const signInUrl = await getSignInUrl()
redirect(signInUrl)
}
return session as typeof session & { user: NonNullable<typeof session.user> }
}
-
Run tsc --noEmit (or in any monorepo package with declaration: true / composite: true / isolatedDeclarations).
-
Observe TS2883 on the requireAuth declaration.
Confirmed in yarn.lock that there are two resolved versions of @workos-inc/node:
"@workos-inc/node@npm:9.2.0": # consumer direct dep
"@workos-inc/node@npm:^9.0.0": # transitive from authkit-nextjs → 9.1.1
yarn dedupe --check '@workos-inc/node' reports the split:
@workos-inc/node@npm:^9.0.0 can be deduped from @workos-inc/node@npm:9.1.1 to @workos-inc/node@npm:9.2.0
Expected behavior
tsc should emit a portable declaration. authkit-nextjs's public types should resolve to a single canonical copy of @workos-inc/node's types regardless of the consumer's resolved version, so that any inferred type referencing User / UserInfo / Session / HandleAuthSuccessData is namable from a stable path.
Root cause
@workos-inc/node is declared in dependencies (https://github.com/workos/authkit-nextjs/blob/main/package.json#L41), but its types are surfaced into authkit-nextjs's public-API interfaces in src/interfaces.ts:
import type { AuthenticationResponse, OauthTokens, User } from '@workos-inc/node';
export interface Session { user: User; ... }
export interface UserInfo { user: User; ... }
export interface HandleAuthSuccessData extends Session {
oauthTokens?: OauthTokens;
authenticationMethod?: AuthenticationResponse['authenticationMethod'];
...
}
A regular dependencies entry on a SDK whose types appear in the public API allows the package manager to install a separate nested copy whenever the consumer's resolved version diverges. The same hazard exists with next and react — and authkit-nextjs already declares both as peerDependencies for exactly this reason.
Proposed fix
Move @workos-inc/node from dependencies to peerDependencies. The peer-dep contract forces a single resolved copy in the consumer tree by construction. PR coming.
This is a breaking change, but in practice the impact is small: every authkit-nextjs consumer already has to call @workos-inc/node directly for the parts of the WorkOS SDK that authkit doesn't wrap (organization management, user management, FGA, audit logs, etc.).
Workaround (for anyone hitting this today)
yarn dedupe '@workos-inc/node' in the consumer's repo collapses the duplicate, and either a resolutions pin or a CI-side yarn dedupe --check '@workos-inc/node' step (run after install) prevents the regression from recurring on future Dependabot bumps.
Environment
authkit-nextjs version: 4.0.1 (also affects all 4.x; same class of bug applied to earlier majors with their own @workos-inc/node ranges)
@workos-inc/node versions involved: 9.1.1 (transitive) vs 9.2.0 (consumer direct)
- Next.js version: any
- TypeScript version: 6.0.x (also reproduces on 5.x with the same diagnostic code)
- Package manager: Yarn 4.14.1 with
nodeLinker: node-modules (the same hazard exists on npm/pnpm whenever versions split)
- OS: macOS / Linux (build-time only — not runtime, not browser-dependent)
Additional context
Same root cause manifested as TS2742 on earlier versions before TS6 changed the diagnostic. Closed issue #181 (1.x era) was a related-but-different surfacing of the public-types-export problem.
Describe the bug
TypeScript emits
TS2883(and on some configurations, the relatedTS2742) on consumer code that infers return types fromwithAuth()orrefreshSession():The error reproduces whenever the consumer's resolved version of
@workos-inc/nodediffers from the version that satisfies authkit-nextjs's transitive^9.0.0range. Package managers then install a duplicate nested copy undernode_modules/@workos-inc/authkit-nextjs/node_modules/@workos-inc/node/, and TypeScript can no longer write a portable declaration for any inferred type that surfacesUser(orOauthTokens,AuthenticationResponse) through the public API.To Reproduce
In a Next.js project, install
@workos-inc/authkit-nextjs@^4.0.1and pin@workos-inc/nodedirectly to a version that doesn't match^9.0.0's currently-resolved point version, e.g.9.2.0while authkit-nextjs's transitive resolution is still at9.1.1. With Yarn 4 + node-modules linker this is whatdependabot[bot]produces every time it bumps the direct pin.Write any function whose return type is inferred from
withAuth(). A minimal repro:Run
tsc --noEmit(or in any monorepo package withdeclaration: true/composite: true/isolatedDeclarations).Observe
TS2883on therequireAuthdeclaration.Confirmed in
yarn.lockthat there are two resolved versions of@workos-inc/node:yarn dedupe --check '@workos-inc/node'reports the split:Expected behavior
tscshould emit a portable declaration. authkit-nextjs's public types should resolve to a single canonical copy of@workos-inc/node's types regardless of the consumer's resolved version, so that any inferred type referencingUser/UserInfo/Session/HandleAuthSuccessDatais namable from a stable path.Root cause
@workos-inc/nodeis declared independencies(https://github.com/workos/authkit-nextjs/blob/main/package.json#L41), but its types are surfaced into authkit-nextjs's public-API interfaces insrc/interfaces.ts:A regular
dependenciesentry on a SDK whose types appear in the public API allows the package manager to install a separate nested copy whenever the consumer's resolved version diverges. The same hazard exists withnextandreact— and authkit-nextjs already declares both aspeerDependenciesfor exactly this reason.Proposed fix
Move
@workos-inc/nodefromdependenciestopeerDependencies. The peer-dep contract forces a single resolved copy in the consumer tree by construction. PR coming.This is a breaking change, but in practice the impact is small: every authkit-nextjs consumer already has to call
@workos-inc/nodedirectly for the parts of the WorkOS SDK that authkit doesn't wrap (organization management, user management, FGA, audit logs, etc.).Workaround (for anyone hitting this today)
yarn dedupe '@workos-inc/node'in the consumer's repo collapses the duplicate, and either aresolutionspin or a CI-sideyarn dedupe --check '@workos-inc/node'step (run after install) prevents the regression from recurring on future Dependabot bumps.Environment
authkit-nextjsversion: 4.0.1 (also affects all 4.x; same class of bug applied to earlier majors with their own@workos-inc/noderanges)@workos-inc/nodeversions involved: 9.1.1 (transitive) vs 9.2.0 (consumer direct)nodeLinker: node-modules(the same hazard exists on npm/pnpm whenever versions split)Additional context
Same root cause manifested as
TS2742on earlier versions before TS6 changed the diagnostic. Closed issue #181 (1.x era) was a related-but-different surfacing of the public-types-export problem.