HelloJohn / docs
Quickstart

Quickstart — Node.js

Add HelloJohn token verification to your Node.js backend in 10 minutes. Works with Express, Fastify, Hono, and any Node.js HTTP server.

Time: ~10 minutes Prerequisites: A HelloJohn account (Cloud) or a self-hosted server running locally. A frontend app already using a HelloJohn SDK.

Install the SDK

npm install @hellojohn/node
yarn add @hellojohn/node
pnpm add @hellojohn/node

Initialize the client

Create a shared HelloJohn client and export it for use throughout your app:

src/lib/hellojohn.ts
import { HelloJohn } from '@hellojohn/node'

export const hellojohn = new HelloJohn({
  secretKey: process.env.HELLOJOHN_SECRET_KEY!,
})

Your Secret Key (sk_...) must never be exposed to the browser. It is for server-side use only. Store it as an environment variable.

Verify a token (Express)

Use hellojohn.verifyToken() to authenticate incoming requests:

src/middleware/auth.ts
import { Request, Response, NextFunction } from 'express'
import { hellojohn } from '../lib/hellojohn'

export async function requireAuth(
  req: Request,
  res: Response,
  next: NextFunction,
) {
  const token = req.headers.authorization?.replace('Bearer ', '')

  if (!token) {
    return res.status(401).json({ error: 'Unauthorized' })
  }

  try {
    const payload = await hellojohn.verifyToken(token)
    res.locals.userId = payload.sub
    next()
  } catch {
    return res.status(401).json({ error: 'Invalid token' })
  }
}

Apply the middleware to protected routes:

src/routes/profile.ts
import { Router } from 'express'
import { requireAuth } from '../middleware/auth'

const router = Router()

router.get('/profile', requireAuth, async (req, res) => {
  const userId = res.locals.userId

  // Fetch user data with the verified userId
  res.json({ userId })
})

export default router

Verify a token (Fastify)

src/plugins/auth.ts
import { FastifyPluginAsync } from 'fastify'
import fp from 'fastify-plugin'
import { hellojohn } from '../lib/hellojohn'

const authPlugin: FastifyPluginAsync = async (fastify) => {
  fastify.addHook('onRequest', async (request, reply) => {
    const token = request.headers.authorization?.replace('Bearer ', '')
    if (!token) {
      reply.status(401).send({ error: 'Unauthorized' })
      return
    }

    try {
      const payload = await hellojohn.verifyToken(token)
      request.userId = payload.sub
    } catch {
      reply.status(401).send({ error: 'Invalid token' })
    }
  })
}

export default fp(authPlugin)

Get the full user object

Optionally fetch the complete user profile after verifying the token:

src/routes/profile.ts
router.get('/me', requireAuth, async (req, res) => {
  const userId = res.locals.userId

  const user = await hellojohn.users.getUser(userId)

  res.json({
    id: user.id,
    email: user.email,
    name: user.name,
  })
})

How token verification works

HelloJohn issues EdDSA-signed JWTs. The verifyToken() method:

  1. Fetches the JWKS (JSON Web Key Set) from your HelloJohn instance (cached automatically)
  2. Verifies the token signature using the public key
  3. Validates expiry, issuer, and audience claims
  4. Returns the decoded payload — no database lookup needed

Next steps

On this page