Authaz logoAuthaz
DocumentationAPI Reference
  • Get Started

    • Authaz
    • Core Concepts
    • Set up your app
    • Quickstart — cURL
  • Authentication

    • Authentication Settings
    • Signup
    • Invitations
    • Password Authentication
    • Multi-Factor Auth
    • Magic Link
    • OAuth / Social Login
    • Passkey (WebAuthn)
    • SAML SSO
    • Machine-to-Machine (M2M)
    • API Keys
  • Authorization

    • Authorization
    • Resources
    • Policies
    • Roles
    • Access Explorer
  • Tenancy

    • Multi-tenancy
    • Tenancy Customization
  • Brand & Host

    • Branding
    • Custom Domains
    • Communications & Email Templates
  • Operate

    • Users
    • Analytics
    • Audit Logs
    • Application Settings
  • SDK Quickstarts

    • Quickstart — Next.js
    • Quickstart — React SPA
    • Quickstart — Hono
    • Quickstart — .NET (Authaz.Sdk)
  • Recipes

    • Recipes & Cookbook
    • Next.js — first integration
    • Next.js — B2B SaaS (multi-tenant)
    • Hono — first integration
    • Hono — B2B SaaS (multi-tenant)
    • React SPA — first integration
    • React SPA — B2B SaaS (multi-tenant)
    • .NET — first integration
    • .NET — B2B SaaS (multi-tenant)
  • Reference

    • Tokens
    • API Reference
    • Errors & Troubleshooting
  • Documentation

    • How Authaz is Built
  1. Authaz
  2. Docs
  3. Recipes
  4. Hono — first integration

Recipes

Hono — first integration

2 min read·Updated Jun 19, 2026

← All recipes · First time? Set up your app (60 seconds — keys + redirect URI)

A Hono backend that signs a user in via Authaz Sign-In, exposes a protected JSON endpoint, and lets them log out. Single-tenant, password provider, no roles.

1. What you'll build#

A Hono API where GET / is public, GET /me returns the signed-in user, and GET /protected requires a valid Authaz session. Runs on Node or Bun.

2. Application setup#

In the Authaz Dashboard:

  1. New application → name it, choose Single-tenant.
  2. Note the Client ID and Client Secret.
  3. Under Auth Flow Configuration, add http://localhost:3000/auth/callback as an allowed callback URL.
Previous
Next.js — B2B SaaS (multi-tenant)
Next
Hono — B2B SaaS (multi-tenant)

…or via the Management API:

POST https://your-app.authaz.io/api/v1/applications
X-API-Key: mgmt_01h...
Content-Type: application/json
 
{ "name": "my-hono-api", "tenancy_type": "single_tenant" }

3. Install#

pnpm add hono @authaz/hono
pnpm add -D @hono/node-server tsx

4. Configure#

.env:

AUTHAZ_CLIENT_ID=app_01h...
AUTHAZ_CLIENT_SECRET=secret_...
AUTHAZ_ORGANIZATION_ID=0199...
AUTHAZ_API_KEY=mgmt_01h...

5. Wire it up#

src/index.ts:

import { Hono } from "hono";
import { serve } from "@hono/node-server";
import {
  createAuthazHandler,
  createAuthMiddleware,
  isAuthenticated,
} from "@authaz/hono";
 
const app = new Hono();
 
// Mount the Authaz handler at /api/auth/*
const authaz = createAuthazHandler({
  clientId: process.env.AUTHAZ_CLIENT_ID!,
  clientSecret: process.env.AUTHAZ_CLIENT_SECRET!,
  organizationId: process.env.AUTHAZ_ORGANIZATION_ID!,
});
app.route("/api/auth", authaz);
 
// Public route
app.get("/", (c) => c.text("Welcome — POST /api/auth/login to sign in."));
 
// Protect /protected and /me with the auth middleware
app.use(
  "*",
  createAuthMiddleware({
    publicPaths: ["/", "/api/auth/*", "/auth/callback"],
    loginPath: "/api/auth/login",
  })
);
 
app.get("/me", async (c) => {
  if (!isAuthenticated(c)) return c.json({ error: "unauthorized" }, 401);
  // The handler also exposes /api/auth/me — redirect for parity
  return c.redirect("/api/auth/me");
});
 
app.get("/protected", (c) =>
  c.json({ message: "You are signed in to Authaz." })
);
 
serve({ fetch: app.fetch, port: 3000 });
console.log("Listening on http://localhost:3000");

The handler exposes /api/auth/login, /api/auth/callback (POST), /api/auth/logout, /api/auth/me, /api/auth/refresh. The OAuth callback bridge page (a tiny client form that POSTs the code) is the same as the Next.js recipe step 5; host it on whatever frontend you pair Hono with.

6. Read the user#

getAccessToken(c) returns the cookie token; pair it with the /api/auth/me call from your client, or call createAuthazHelpers({ organizationId, apiKey }).getUser() server-side:

import { createAuthazHelpers } from "@authaz/hono";
 
const helpers = createAuthazHelpers({
  organizationId: process.env.AUTHAZ_ORGANIZATION_ID!,
  apiKey: process.env.AUTHAZ_API_KEY!,
});
 
app.get("/who-am-i", async (c) => {
  const user = await helpers.getUser(c);
  if (!user) return c.json({ error: "unauthorized" }, 401);
  return c.json({ id: user.id, email: user.email });
});

7. Protect a route#

The createAuthMiddleware wraps * already. For per-route protection, check the cookie directly with isAuthenticated(c):

app.get("/private", (c) => {
  if (!isAuthenticated(c)) return c.json({ error: "unauthorized" }, 401);
  return c.json({ secret: 42 });
});

8. Common gotchas#

  • Callback URL must match exactly. A trailing slash, http vs https, or a different port all fail. Register every dev/staging/prod URL.
  • You still need a callback page. Authaz redirects to a page (GET), which POSTs the code into /api/auth/callback. Hono only handles the API side — pair it with a frontend (or a tiny static HTML page) for the bridge.
  • Cookies need HTTPS in production. The SDK sets Secure automatically; behind a load balancer make sure x-forwarded-proto: https reaches the app.
  • Logout is POST. Use a <form method="POST" action="/api/auth/logout">, not a GET link.
  • Don't expose clientSecret to the browser. It's a server-only env var. The Hono handler is fine; never inline the secret into a client bundle.

9. Next steps#

  • Multi-tenant Hono recipe — same shape with tenant-scoped permission checks
  • React SPA recipe — pair this Hono backend with a React frontend
  • Authentication providers — add Google, magic link, passkey