@bklarjs/jwt
Version:
A JWT-based authentication middleware designed for the Bklar web framework.
176 lines (131 loc) • 5.94 kB
Markdown
# /jwt
[](https://www.npmjs.com/package/@bklarjs/jwt)
[](https://opensource.org/licenses/MIT)
[](https://github.com/bernabedev/bklar/actions)
Official JWT (JSON Web Token) authentication middleware for the **[bklar](https://www.npmjs.com/package/bklar)** framework.
It allows you to protect routes, verify tokens, and handle user authentication with a clear, simple, and secure API.
---
## ✨ Features
- 🔒 **Secure by Default:** Built on top of `jose`, a modern, secure, and Web Cryptography API-based library for JWTs.
- 🧩 **Simple Integration:** Add authentication to any route with just a few lines of code.
- 🔧 **Flexible Configuration:** Customize token retrieval, validation algorithms, and optional authentication (`passthrough` mode).
- 🧰 **Helper Functions Included:** Comes with `sign`, `verify`, and `decode` helpers for a complete authentication solution out of the box.
- 🛡️ **Full TypeScript Support:** Automatically augments the `bklar` Context to provide a strongly-typed `ctx.state.jwt` payload in your protected routes.
## 📦 Installation
This package is designed to work with `bklar`. You'll need both installed in your project.
```bash
bun add bklar /jwt
```
## 🚀 Usage
Using the middleware involves two main steps: creating tokens (e.g., during login) and verifying them to protect routes.
### 1. Protecting a Route
First, create an instance of the JWT middleware and apply it to a route you want to protect.
```typescript
import { Bklar } from "bklar";
import { jwt } from "@bklarjs/jwt";
const app = Bklar();
// It's highly recommended to use an environment variable for your secret.
const JWT_SECRET = "a-very-strong-secret-key";
// Create an instance of the auth middleware with your secret
const authMiddleware = jwt({ secret: JWT_SECRET });
app.get(
"/profile",
(ctx) => {
// If we reach this handler, the token is valid.
// The decoded JWT payload is available at `ctx.state.jwt`.
const userPayload = ctx.state.jwt;
return ctx.json({
message: "Welcome to your protected profile!",
user: userPayload,
});
},
{
middlewares: [authMiddleware],
}
);
app.listen(3000);
```
To access this route, a client must provide a valid JWT in the `Authorization` header:
`Authorization: Bearer <your-token>`
### 2. Creating a Token (Login Flow)
To get a token, you typically create a `/login` endpoint. This package includes a `sign` helper to make this easy.
```typescript
import { Bklar } from "bklar";
import { jwt, sign } from "@bklarjs/jwt";
import { z } from "zod";
const app = Bklar();
const JWT_SECRET = "a-very-strong-secret-key";
// Example user service (in a real app, this would query a database)
const UserService = {
login: async (email: string, pass: string) => {
if (email === "user@example.com" && pass === "password123") {
return { id: "user_123", email, role: "user" };
}
return null;
},
};
// Login endpoint to generate a token
app.post(
"/login",
async (ctx) => {
const { email, password } = ctx.body;
const user = await UserService.login(email, password);
if (!user) {
// The bklar error handler will catch this and respond with a 401.
throw new UnauthorizedError("Invalid email or password");
}
// Sign a new token for the authenticated user
const token = await sign(
{ sub: user.id, email: user.email, role: user.role },
JWT_SECRET,
"HS256",
{ expiresIn: "1h" } // Token is valid for 1 hour
);
return ctx.json({ token });
},
{
schemas: {
body: z.object({
email: z.string().email(),
password: z.string(),
}),
},
}
);
app.listen(3000);
```
## ⚙️ Configuration Options
The `jwt()` factory accepts an options object:
- `secret`: (Required) A `string` or `Uint8Array` used to sign and verify tokens.
- `algorithms`: An optional array of allowed signing algorithms (e.g., `['HS256', 'HS512']`). Defaults to `['HS256']`.
- `passthrough`: A boolean. If `true`, the middleware will not throw an error if the token is missing or invalid. `ctx.state.jwt` will simply be `undefined`. Useful for routes with optional authentication. Defaults to `false`.
- `getToken`: A custom function `(ctx: Context) => string | undefined` to extract the token from the request. By default, it looks for a Bearer token in the `Authorization` header.
### Example: Optional Authentication
```typescript
const optionalAuth = jwt({ secret: JWT_SECRET, passthrough: true });
app.get(
"/posts/:id",
(ctx) => {
if (ctx.state.jwt) {
// User is logged in, show personalized content
return ctx.json({
content: "A post.",
personalizedFor: ctx.state.jwt.sub,
});
}
// User is a guest, show public content
return ctx.json({ content: "A post." });
},
{ middlewares: [optionalAuth] }
);
```
## 🧰 API Reference
This package exports the following:
- `jwt(options: JWTOptions): Middleware`: The main factory function that creates the authentication middleware.
- `sign(payload, secret, alg, options)`: An async function to create and sign a new JWT.
- `verify(token, secret, algorithms)`: An async function to verify a token. It throws an error if invalid or returns the payload if valid.
- `decode(token)`: A synchronous function that decodes a token's payload _without_ verifying its signature. **Use with caution.**
## 🤝 Contributing
Contributions are welcome! Please open an [issue](https://github.com/bernabedev/bklar/issues) or submit a Pull Request to the main `bklar` repository.
## 📄 License
This project is licensed under the **MIT License**.