hono-openid-connect
v2.5.0
Published
OpenID Connect middleware for Hono
Maintainers
Readme
Hono OpenID Connect Middleware
An OpenID Connect (OIDC) authentication middleware for Hono web framework. Built on top of openid-client, this package provides a simple way to secure your Hono applications using standard OIDC authentication flows.
This middleware enables seamless integration with OpenID Connect providers like Auth0, Okta, Google, and others with minimal configuration. It draws inspiration from express-openid-connect, though its configuration and session cookie implementation are not compatible.
Installation
npm install hono-openid-connectBasic Usage
The simplest way to secure your Hono application is to implement the middleware at the application level. By default, all routes will require authentication.
import { Hono } from "hono";
import { auth } from "hono-openid-connect";
const app = new Hono();
// Configure auth middleware with session options
app.use(
auth({
issuerBaseURL: process.env.ISSUER_BASE_URL,
clientID: process.env.CLIENT_ID,
clientSecret: process.env.CLIENT_SECRET,
baseURL: process.env.BASE_URL,
session: {
encryptionKey: "password_at_least_32_characters_long",
},
}),
);
app.get("/", (c) => {
return c.text(`Hello ${c.var.oidc?.claims?.name}!`);
});
export default app;Features
- OpenID Connect Authentication Flow: Implements the standard OIDC authorization code flow
- Session Management: Built-in session support with configurable cookie settings
- Configurable Routes: Customize login, callback, and logout route paths
- Selective Protection: Choose which routes require authentication with the
authRequiredoption - Token Management: Handles access tokens, ID tokens and refresh tokens
- User Information: Automatically fetches and provides user profile data from the UserInfo endpoint
- Claim-Based Authorization: Middleware for authorizing based on claims from tokens
- PKCE Support: Implements Proof Key for Code Exchange for enhanced security
- Environment Flexibility: Works across various environments including Node.js, Bun, Cloudflare Workers, and more
Configuration Options
Required Configuration
| Option | Type | Description |
| --------------- | -------- | ---------------------------------------------------------------- |
| issuerBaseURL | string | Base URL of the OIDC provider (e.g., https://auth.example.com) |
| baseURL | string | Base URL of your application (e.g., https://myapp.com) |
| clientID | string | Client ID provided by your OIDC provider |
Optional Configuration
| Option | Type | Default | Description |
| ----------------------------- | --------------- | ----------- | ------------------------------------------------------------------------------------ |
| clientSecret | string | undefined | Client Secret provided by your OIDC provider (required for most flows) |
| authRequired | boolean | true | Whether authentication is required for all routes |
| idpLogout | boolean | false | Whether to perform logout at the identity provider when logging out |
| pushedAuthorizationRequests | boolean | false | Enable Pushed Authorization Requests (PAR) |
| customRoutes | Array<string> | [] | Specify which built-in routes to skip (options: 'login', 'callback', 'logout') |
Routes Configuration
You can customize the paths for login, callback, and logout endpoints:
app.use(
auth({
// ...required options
routes: {
login: "/custom-login",
callback: "/auth-callback",
logout: "/sign-out",
},
}),
);Session Configuration
The middleware uses hono-sessions for session management. You can configure session options or disable sessions entirely:
app.use(
auth({
// ...required options
session: {
encryptionKey: "your-secure-encryption-key-minimum-32-chars",
sessionCookieName: "my_session",
cookieOptions: {
sameSite: "Lax",
path: "/",
httpOnly: true,
secure: process.env.NODE_ENV === "production",
},
},
}),
);To use your own instance of hono-sessions:
app.use(sessionMiddleware({}));
app.use(
auth({
// ...required options
session: false,
}),
);Authorization Parameters
You can customize the parameters sent to the authorization endpoint:
app.use(
auth({
// ...required options
authorizationParams: {
response_type: "code",
scope: "openid profile email",
response_mode: "query",
},
}),
);Error handling
You can catch OIDCException errors and handle them in your application. This is useful for logging or displaying custom error messages.
import { OIDCException } from "hono-openid-connect";
app.onError((err, c) => {
// Handle OIDC-specific errors
if (err instanceof OIDCException) {
console.log(err);
if (process.env.NODE_ENV === "development") {
return err.getResponse();
}
return c.text(`Authentication Error`, 500);
}
// Handle other errors
return c.text(`Internal Server Error: ${err.message}`, 500);
});Configuration thru environment variables
You can also configure the middleware using environment variables. The following environment variables are supported:
- OIDC_ISSUER_URL: The issuer URL of the OpenID Connect provider (e.g.,
https://auth.example.com) - OIDC_CLIENT_ID: The client ID provided by your OIDC provider
- OIDC_CLIENT_SECRET?: The client secret provided by your OIDC provider (required for most flows)
- BASE_URL: The base URL of your application (e.g.,
https://myapp.com)
In order to make the parameters of the middleware optional so you can use auth({}), your process.env must define the properties as follows:
delcare global {
namespace NodeJS {
interface ProcessEnv {
OIDC_ISSUER_URL: string;
OIDC_CLIENT_ID: string;
OIDC_CLIENT_SECRET?: string;
BASE_URL: string;
OIDC_SESSION_ENCRYPTION_KEY: string;
}
}
}You automatically achieve this in Cloudflare's wrangler if you use:
"compatibility_flags": [
"nodejs_compat",
"nodejs_compat_populate_process_env"
],Advanced Usage
Selective Route Protection
Only protect specific routes:
import { Hono } from "hono";
import { auth, requiresAuth } from "hono-openid-connect";
const app = new Hono();
app.use(
auth({
// ...required options
authRequired: false,
}),
);
// Public route - no authentication required
app.get("/", (c) => {
return c.text("This is a public page");
});
// Protected route - authentication required
app.use("/profile/*", requiresAuth());
app.get("/profile", (c) => {
const user = c.var.oidc.user;
return c.text(`Hello ${user.name || user.sub}!`);
});Silent Login Attempt
Try to authenticate silently without user interaction:
import { Hono } from "hono";
import { auth, attemptSilentLogin } from "hono-openid-connect";
const app = new Hono();
app.use(
auth({
/* ...options */
authRequired: false,
}),
);
app.get("/", attemptSilentLogin(), async (c) => {
if (c.var.oidc?.isAuthenticated) {
return c.text(`Hello ${c.var.oidc.user.name}!`);
}
return c.text("You are not logged in");
});Advanced Login Options
The login middleware supports several advanced options:
import { login } from "hono-openid-connect";
// Custom login options
app.get("/custom-login", async (c) => {
return login({
// Redirect user to this URL after successful authentication
redirectAfterLogin: "/dashboard",
// Additional authorization parameters to send to the identity provider
authorizationParams: {
prompt: "consent",
acr_values: "level2",
login_hint: "[email protected]",
},
// Forward specific query parameters from the login request to the authorization request
forwardQueryParams: ["ui_locales", "login_hint", "campaign"],
// Attempt silent authentication (no user interaction)
silent: false,
})(c);
});With forwardQueryParams, you can pass query parameters from the login request to the authorization request. This is useful for:
- Passing UI locale preferences (
ui_locales) - Forwarding login hints to the identity provider
- Maintaining tracking parameters throughout the authentication flow
- Supporting custom parameters your identity provider accepts
Current Limitations
- Backchannel Logout: Unlike express-openid-connect, this middleware does not currently support backchannel logout.
- JWT Response Mode: Currently supports standard response modes but not JWT response mode.
- Dynamic Client Registration: Manual client registration is required.
Context Variables
The middleware adds the following to the Hono context (c.var):
c.var.oidc.isAuthenticated: Boolean indicating if the user is authenticatedc.var.oidc.claims: All claims from the ID tokenc.var.oidc.tokens: The entire token exchange response:c.var.oidc.tokens.id_token: Raw ID tokenc.var.oidc.tokens.access_token: Access token (if available)c.var.oidc.tokens.refresh_token: Refresh token (if available)
c.var.oidc.isExpired: Boolean indicating if the access token is expiredc.var.oidc.fetchUserInfo(): Fetches user info from the UserInfo endpoint.c.var.oidc.refresh(): Refreshes the access token using the refresh token (if available).c.var.oidcClient: The openid-client authorization server configuration object. This is helpful if you need to invoke a method of the openid-client directly.
License
MIT 2025 - José F. Romaniello
