Skip to content

Hono Variables in AuthHero ​

AuthHero uses Hono's context variables system to store and share data across middleware and route handlers. This document describes the available variables and how to use them.

Overview ​

Variables in AuthHero are stored in the Hono context (ctx.var) and provide a type-safe way to access request-specific data throughout the request lifecycle. All variables are automatically populated by middleware and are available in route handlers without additional setup.

Available Variables ​

Core Variables ​

VariableTypeDescriptionSet By
tenant_idstringThe current tenant identifier. Resolution order is documented in Tenant Resolution Chain.tenantMiddleware
ipstringClient IP address (from x-real-ip header)clientInfoMiddleware
client_idstring?OAuth client identifierVarious auth flows
user_idstring?Current user identifierAuth middleware
usernamestring?Username/email for current requestAuth flows
connectionstring?Authentication connection nameAuth flows
custom_domainstring?Custom domain for the requestDomain middleware

Authentication Variables ​

VariableTypeDescriptionSet By
user{ sub: string; tenant_id: string }?Authenticated user infoauthMiddleware
loginSessionLoginSession?Current login sessionLogin flows

Client Information Variables ​

These variables are automatically extracted from HTTP headers and query parameters by the clientInfoMiddleware:

VariableTypeDescriptionSource
auth0_clientAuth0ClientInfo?Parsed Auth0 client informationauth0Client query parameter
useragentstring?User agent stringuser-agent header
countryCodeCountryCode?ISO country codecf-ipcountry header (CloudFlare)

Auth0 Client Structure ​

The auth0_client variable contains parsed information from the auth0Client query parameter. The middleware supports both JSON and string formats:

JSON Format (preferred):

json
{
  "name": "auth0-spa-js",
  "version": "1.13.6",
  "env": {
    "node": "16.14.0"
  }
}

String Format (legacy support):

auth0-spa-js/1.13.6 (env: node/16.14.0)

Both formats are parsed into the same TypeScript structure:

typescript
type Auth0ClientInfo = {
  name: string; // e.g., "auth0-spa-js"
  version: string; // e.g., "1.13.6"
  env?: {
    // Optional environment info
    node?: string; // e.g., "16.14.0"
  };
};

The parsing uses Zod schemas for validation, ensuring type safety and catching malformed client information gracefully.

Debug Variables ​

VariableTypeDescriptionSet By
bodyany?Request body (for debugging)Request processing
logstring?Log context informationLogging middleware

Usage in Route Handlers ​

Basic Access ​

typescript
app.get("/example", async (ctx) => {
  // Access variables directly
  const tenantId = ctx.get("tenant_id");
  const clientIp = ctx.get("ip");
  const userAgent = ctx.get("useragent");
  const auth0Client = ctx.get("auth0_client");

  console.log(`Request from ${clientIp} in tenant ${tenantId}`);

  if (auth0Client) {
    console.log(`Client: ${auth0Client.name} v${auth0Client.version}`);
  }

  return ctx.json({ message: "Success" });
});

Type-Safe Access ​

The variables are fully typed through the Variables interface:

typescript
import { Variables } from "@authhero/authhero";

app.get("/typed-example", async (ctx: Context<{ Variables: Variables }>) => {
  // TypeScript will provide full autocomplete and type checking
  const user = ctx.get("user"); // { sub: string; tenant_id: string } | undefined
  const countryCode = ctx.get("countryCode"); // CountryCode | undefined

  if (user) {
    console.log(`Authenticated user: ${user.sub}`);
  }

  return ctx.json({ authenticated: !!user });
});

Setting Variables ​

Variables can be set by middleware or route handlers:

typescript
app.use(async (ctx, next) => {
  // Set a custom variable
  ctx.set("custom_data", { timestamp: Date.now() });
  await next();
});

app.post("/login", async (ctx) => {
  // Set user context after authentication
  ctx.set("user_id", "user123");
  ctx.set("username", "[email protected]");

  return ctx.json({ success: true });
});

Utility Functions ​

AuthHero provides several utility functions for working with client information variables:

getClientInfoFromContext ​

Get all client information as a structured object:

typescript
import { getClientInfoFromContext } from "@authhero/authhero";

app.get("/client-info", async (ctx) => {
  const clientInfo = getClientInfoFromContext(ctx);

  return ctx.json({
    auth0Client: clientInfo.auth0_client,
    ip: clientInfo.ip,
    userAgent: clientInfo.useragent,
    country: clientInfo.countryCode,
  });
});

getClientInfoWithStringAuth0Client ​

Get client information with auth0Client formatted as a string (for backward compatibility):

typescript
import { getClientInfoWithStringAuth0Client } from "@authhero/authhero";

app.get("/legacy-client-info", async (ctx) => {
  const clientInfo = getClientInfoWithStringAuth0Client(ctx);

  return ctx.json({
    auth0Client: clientInfo.auth0Client, // String format: "auth0-spa-js/1.13.6"
    ip: clientInfo.ip,
    userAgent: clientInfo.useragent,
  });
});

stringifyAuth0Client ​

Convert structured auth0_client to string format:

typescript
import { stringifyAuth0Client } from "@authhero/authhero";

app.get("/auth0-client-string", async (ctx) => {
  const auth0Client = ctx.get("auth0_client");
  const auth0ClientString = stringifyAuth0Client(auth0Client);

  return ctx.json({ clientString: auth0ClientString });
});

Middleware Chain ​

Variables are populated by middleware in this order:

  1. Data Setup - Database adapters and caching
  2. Client Info Middleware - Extracts ip, useragent, auth0_client, countryCode
  3. Tenant Middleware - Sets tenant_id, custom_domain
  4. Auth Middleware - Sets user, authentication context

This ensures that all variables are available when your route handlers execute.

Best Practices ​

1. Always Check for Undefined ​

Variables can be undefined, so always check before using:

typescript
const user = ctx.get("user");
if (user) {
  // Safe to use user.sub and user.tenant_id
  console.log(`User ${user.sub} in tenant ${user.tenant_id}`);
}

2. Use Type Guards ​

For complex variables, use type guards:

typescript
const auth0Client = ctx.get("auth0_client");
if (auth0Client?.name && auth0Client?.version) {
  console.log(`Client: ${auth0Client.name} v${auth0Client.version}`);
}

3. Prefer Utility Functions ​

Use the provided utility functions instead of accessing variables directly when possible:

typescript
// Preferred
const clientInfo = getClientInfoFromContext(ctx);

// Instead of
const ip = ctx.get("ip");
const userAgent = ctx.get("useragent");
const auth0Client = ctx.get("auth0_client");

4. Document Custom Variables ​

If you set custom variables in your middleware, document them clearly:

typescript
// Custom middleware that sets application-specific variables
app.use(async (ctx, next) => {
  ctx.set("request_id", generateRequestId());
  ctx.set("feature_flags", await getFeatureFlags(ctx.get("tenant_id")));
  await next();
});

Dual-licensed: AGPL-3.0-only or commercial license.