Skip to content

bug(types): fastify.jwt always typed as JWT even with namespace mode #395

Description

@SkyTik

Bug

When registering the plugin with namespace option, fastify.jwt becomes a { [namespace]: JWT } map at runtime. However, TypeScript always types it as JWT (the single decorator shape).

Current type declaration (types/jwt.d.ts:16-18):

interface FastifyInstance {
  jwt: fastifyJwt.JWT  // hardcoded — ignores namespace mode
}

Reproduction

import fastify from 'fastify'
import jwt from '@fastify/jwt'

const app = fastify()
app.register(jwt, { secret: 'auth-secret', namespace: 'auth' })
app.register(jwt, { secret: 'admin-secret', namespace: 'admin' })

app.ready().then(() => {
  // Runtime: works ✅
  console.log(app.jwt.auth.sign({ sub: '1' }))
  console.log(app.jwt.admin.sign({ sub: '2' }))

  // TypeScript: ❌ Property 'auth' does not exist on type 'JWT'
  // TypeScript: ❌ Property 'admin' does not exist on type 'JWT'
})

Expected behavior

fastify.jwt should be typed as { auth: JWT, admin: JWT } when using namespaces, or there should be a documented way (e.g. declaration merging) for users to override the type.

Context

The FastifyJwtNamespace type (line 48-73) correctly handles the request-level decorators (authJwtVerify, authJwtSign, etc.), but the fastify.jwt instance property has no corresponding namespace-aware typing.

Environment

  • @fastify/jwt: latest
  • Node.js: 20+
  • TypeScript: 5.x

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions