0.1.1 • Published 6 months ago

passport-fast-jwt v0.1.1

Weekly downloads
-
License
MIT
Repository
github
Last release
6 months ago

Passport-Fast-JWT

!WARNING This is still very new module. There might be a lot of issues and this might not work in every use case. If something does not work just let me know and raise an issue.

Build status

A Passport strategy for authenticating with JSON Web tokens using fast-jwt library.

This module takes inspiration from widely used passport-jwt by Mike Nicholson. Main difference is that this is written entirely in TypeScript, relies on using fast-jwt instead of jsonwebtoken and most of all, thanks to fast-jwt, supports verifying tokens signed with EdDSA algorithm. Later I might change this so that you can pass in a JWT verifier created with any library, but for now only verifiers created with fast-jwt is supported and tested.

Install

npm install --save passport-fast-jwt
pnpm add passport-fast-jwt
yarn add passport-fast-jwt

Usage

The first argument is a JWT verifier function created with fast-jwt createVerifier or alternatively options to be used when creating one. If the options are passed, the strategy creates a verifier function using fast-jwt with the given options. You can read more about verifier options from fast-jwt docs.

type ConstructionArgumentss = [
  VerifierOptions | Verifier,
  TokenExtractor,
  AfterVerifyCallback,
]

type VerifierOptions = FastJWT.VerifierOptions & {
  key?:
    | string
    | Buffer
    | ((DecodedJwt: FastJWT.DecodedJwt) => Promise<string | Buffer>)
}

type Verifier =
  | typeof FastJWT.VerifierSync
  | ((token: string | Buffer) => Promise<any>)

type TokenExtractor = (request: Express.Request) => string | undefined | null

type AfterVerifyCallback = (
  sections: FastJWT.DecodedJwt,
  doneAuth: Passport.AuthenticateCallback,
  request?: Express.Request,
) => void
const jwtVerifier = FastJWT.createVerifier({ ...verifierOptions })
const tokenExtractor = Extractors.fromHeader("token-header")

passport.use(
  new JwtStrategy(jwtVerifier, tokenExtractor, (sections, done, req) => {
    User.findOne({ id: sections.payload.sub }, (error, user) => {
      if (error) {
        return done(err, false)
      }
      if (!user) {
        return done(null, false, "User not found", 404)
      }
      return done(null, user)
    })
  }),
)
// *-----------* OR *-----------*
const verifierOptions = { key: async () => "secret", cache: true }
const tokenExtractor = Extractors.fromHeader("token-header")

passport.use(
  new JwtStrategy(verifierOptions, tokenExtractor, (sections, done, req) => {
    User.findOne({ id: sections.payload.sub }, (error, user) => {
      if (error) {
        return done(err, false)
      }
      if (!user) {
        return done(null, false, "User not found", 404)
      }
      return done(null, user)
    })
  }),
)

Fast-JWT createVerifier options

All Fast-JWT verifier options can be passed as the fastJwtOptions. However, all options combinations haven't been tested yet, so proceed with caution. If you find any problems with some options, please raise an issue.

Verification callback

Verification callback is the callback function that is called after successful JSON Web Token verification. JWT token sections and a special authentication function, usually called done, are passed into it after succesful JWT verification. Sections are the JWT header, payload, signature and input, the original token as a string or alternatively just the JWT payload, if verifier is created with the option { complete: false }. Done is function that calls the underlying passport success, fail and error methods depending on its arguments.

passport.use(
  new JwtStrategy(jwtVerifier, tokenExtractor, (sections, done) => {
    User.findOne({ id: sections.payload.sub }, (error, user) => {
      if (error) {
        // error is passed --> passport error is called and errs the authentication
        return done(err, false)
      }
      if (!user) {
        // error is null and user is falsy --> passport fail is called and fails the authentication.
        // Note error must not be passed in this case!
        // Additional parameters can be passed as the info and status
        return done(null, false, "User not found", 404)
      }

      // User object is passed and error is null --> passport success is called
      // and user object is assigned into Express.user and user is authenticated
      return done(null, user)
    })
  }),
)

Error handling

Like any other strategy, this also passes any internal error happening in the strategy, practically any error happening during the JWT verification, directly into the Express next function. If you like to have more control over this you can wrap the strategy into a custom middleware function

someRouter.use("/someRoute", (req, res, next) =>
  passport.authenticate(
    "jwt",
    { session: false },
    (err: any, user: Express.User, info: any) => {
      if (err) {
        console.log("Error happened, need to do something to it")
        next(err)
      }
    },
  )(req, res, next),
)

Support

Currently there's quite limited support for Fast-JWT features. As of writing this I have tested only some features.

A non-comprehensive list of supported and non-supported Fast-JWT features:

  • No support for fast-jwt callback style verifier

Secret Keys

Fast-JWT accepts the signing and verifying keys only in PEM format unless you are using secret key as a string. You can create some with openssl:

RSA

openssl genpkey -algorithm rsa -out private.pem && openssl pkey -in private.pem -pubout -out public.pem

EdDSA

openssl genpkey -algorithm ed25519 -out private.pem && openssl pkey -in private.pem -pubout -out public.pem

License

The MIT License

Copyright (c) 2024 Timo Mätäsaho

0.1.1

6 months ago

0.1.0

6 months ago

0.0.24

6 months ago

0.0.22

6 months ago

0.0.21

6 months ago

0.0.20

6 months ago

0.0.19

6 months ago

0.0.18

6 months ago

0.0.17

6 months ago