npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

express-authrouter

v4.0.0

Published

Plug-and-play authentication router for Express + Prisma + JWT

Readme

express-authrouter

npm version license node typescript

Plug-and-play authentication router for Express + Prisma + JWT.

TypeScript types are included out of the box — no @types/ package needed.

Drop it into any Express app and get POST /register and POST /login routes, a protect() middleware for guarded routes, and optional express-validator integration — all in a few lines.


Table of contents


Requirements

| Peer dependency | Minimum version | |---|---| | express | ^4.0.0 | | @prisma/client | ^5.0.0 | | Node.js | 18.0.0 |


Installation

npm install express-authrouter

Quick start

// app.js
import express from 'express'
import { PrismaClient } from '@prisma/client'
import Auth from 'express-authrouter'

const app = express()
const prisma = new PrismaClient()

app.use(express.json())

const auth = new Auth(prisma, process.env.JWT_SECRET, ['email'])

// Public auth routes: POST /auth/register  POST /auth/login
app.use('/auth', auth.routes())

// Protected route
app.get('/profile', auth.protect(), (req, res) => {
  res.json({ userId: req.user.id })
})

app.listen(3000)

Prisma schema

Your schema must have a model with:

  • A unique field for each identity you pass (e.g. email).
  • A password field.
  • An id field (used as the JWT payload).
model User {
  id       Int    @id @default(autoincrement())
  email    String @unique
  password String
}

The model name in camelCase (user, account, etc.) must match the userModel option — defaults to 'user'.


API

new Auth(prisma, secret, identities, options?)

| Parameter | Type | Required | Description | |---|---|---|---| | prisma | PrismaClient | ✅ | Your Prisma client instance. | | secret | string | ✅ | Secret key for signing/verifying JWT tokens. Use an env variable. | | identities | string[] | ✅ | Fields used as unique user identifiers. The first element is used for login lookup. | | options | AuthOptions | — | Optional configuration (see below). |

AuthOptions

| Option | Type | Default | Description | |---|---|---|---| | expiresIn | string | '7d' | JWT expiration. Accepts any value valid for jsonwebtoken (e.g. '1h', '30d'). | | userModel | string | 'user' | Prisma model name in camelCase. Change this if your model is named differently (e.g. 'account'). |

const auth = new Auth(prisma, process.env.JWT_SECRET, ['email', 'username'], {
  expiresIn: '1d',
  userModel: 'user'
})

auth.routes()

Returns an Express Router with:

| Method | Path | Description | |---|---|---| | POST | /register | Creates a new user. Hashes the password and returns a JWT. | | POST | /login | Validates credentials and returns a JWT. |

app.use('/auth', auth.routes())

auth.protect()

Returns a middleware that validates the JWT from the Authorization header.

Authorization: Bearer <token>

On success, the decoded token payload is available at req.user (contains id).

app.get('/dashboard', auth.protect(), (req, res) => {
  res.json({ userId: req.user.id })
})

auth.result()

Returns a middleware compatible with express-validator. Place it after your validator chain to short-circuit with a 400 response if any validation fails.

import { body } from 'express-validator'

app.post(
  '/auth/register',
  body('email').isEmail().normalizeEmail(),
  body('password').isLength({ min: 8 }),
  auth.result(),        // ← returns 400 if validators above failed
)

userModelExists(prisma, userModel?)

A named export you can use as a startup check to verify that your Prisma migrations have been applied before the app starts accepting traffic. It is not run on every request by default.

import Auth, { userModelExists } from 'express-authrouter'

// Fail fast if the table doesn't exist
app.use(userModelExists(prisma))           // defaults to model 'user'
app.use(userModelExists(prisma, 'account'))

app.use('/auth', auth.routes())

HTTP reference

POST /register

Request body

{
  "email": "[email protected]",
  "password": "secret123"
}

Include any extra fields you have in your Prisma model — they are forwarded to prisma.user.create().

Responses

| Status | Body | Meaning | |---|---|---| | 201 | { "token": "..." } | User created. | | 400 | { "error": "..." } | Missing required field. | | 409 | { "error": "email is already taken" } | Identity already exists. | | 500 | { "error": "..." } | Server/database error. |


POST /login

The primary identity (first element of identities) is used for lookup.

Request body

{
  "email": "[email protected]",
  "password": "secret123"
}

Responses

| Status | Body | Meaning | |---|---|---| | 200 | { "token": "..." } | Login successful. | | 400 | { "error": "..." } | Missing field. | | 401 | { "error": "incorrect password" } | Wrong password. | | 404 | { "error": "user not found" } | No user found. | | 500 | { "error": "..." } | Server/database error. |


Protected routes

Send the token in the Authorization header:

Authorization: Bearer eyJhbGci...

Responses

| Status | Body | Meaning | |---|---|---| | 200 | (your handler's response) | Token valid. req.user.id is available. | | 403 | { "error": "no token provided" } | Header missing or malformed. | | 401 | { "error": "..." } | Token invalid or expired. |


Using express-validator

Add validators before mounting the auth router and use auth.result() to short-circuit on errors:

import { body } from 'express-validator'

app.use(
  '/auth',
  body('email').isEmail().withMessage('invalid email').normalizeEmail(),
  body('password').isLength({ min: 8 }).withMessage('password must be at least 8 characters'),
  auth.result(),
  auth.routes()
)

Custom model name

If your Prisma model is not User, pass userModel in the options:

model Account {
  id       Int    @id @default(autoincrement())
  email    String @unique
  password String
}
const auth = new Auth(prisma, process.env.JWT_SECRET, ['email'], {
  userModel: 'account'
})

Error responses

All error responses follow a consistent JSON shape:

{ "error": "descriptive message here" }

Validation errors from auth.result() use:

{ "errors": [ { "msg": "...", "path": "...", ... } ] }

License

MIT — Nelson David Arguedo Ramos (DarkSevenX)