### Install Auth0 Hono SDK Source: https://github.com/auth0-lab/auth0-hono/blob/main/README.md Install the SDK using npm. This command adds the necessary package to your project's dependencies. ```bash npm install @auth0/auth0-hono ``` -------------------------------- ### Database Session Store Implementation Example Source: https://github.com/auth0-lab/auth0-hono/blob/main/_autodocs/types.md An example implementation of a custom SessionStore using a hypothetical database. It shows how to override the abstract methods for session persistence. ```typescript import { SessionStore, StateData } from '@auth0/auth0-hono' class DatabaseSessionStore extends SessionStore { async set(identifier: string, stateData: StateData, deleteSession: boolean, ctx: Context): Promise { if (deleteSession) { await db.sessions.delete(stateData.internal.sid) } else { await db.sessions.upsert(stateData.internal.sid, stateData) } } async get(identifier: string, ctx: Context): Promise { const sessionId = ctx.req.header('x-session-id') return await db.sessions.findById(sessionId) } async delete(identifier: string): Promise { // No-op: deletes are handled via set(..., true) } async deleteByLogoutToken(claims: LogoutTokenClaims, ctx?: Context): Promise { await db.sessions.delete(claims.sub) } } app.use('*', auth0({ session: { secret: '...', store: new DatabaseSessionStore(), }, })) ``` -------------------------------- ### Auth0 Hono Session Configuration Example Source: https://github.com/auth0-lab/auth0-hono/blob/main/_autodocs/types.md Example of how to configure session settings within the auth0() middleware. Demonstrates setting encryption keys, session durations, and custom cookie options. ```typescript app.use('*', auth0({ session: { secret: 'at_least_32_character_encryption_key_string', rolling: true, absoluteDuration: 7 * 24 * 60 * 60, // 7 days inactivityDuration: 2 * 60 * 60, // 2 hours cookie: { name: 'my_session', sameSite: 'lax', secure: true, }, }, })) ``` -------------------------------- ### auth0 Middleware Setup Source: https://github.com/auth0-lab/auth0-hono/blob/main/_autodocs/api-reference/auth0-middleware.md This snippet shows the basic setup of the Auth0 middleware in a Hono application. It registers the middleware on all routes, making protected routes available. ```APIDOC ## auth0 Middleware Setup ### Description This section demonstrates how to integrate the Auth0 middleware into your Hono application. The `auth0()` function returns a `MiddlewareHandler` that, when registered with `app.use()`, automatically handles authentication flows and populates request context with user and session data. ### Method `app.use()` ### Endpoint `*` (all routes) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```typescript import { Hono } from 'hono' import { auth0, requiresAuth } from '@auth0/auth0-hono' const app = new Hono() // Register auth middleware on all routes app.use('*', auth0()) // Public route — no authentication required app.get('/', (c) => c.text('Home')) // Protected route — authentication required app.get('/profile', requiresAuth(), (c) => { const user = c.var.auth0.user return c.json({ name: user?.name, email: user?.email }) }) export default app ``` ### Response #### Success Response (200) Responses vary based on the route. The middleware itself does not directly return a response but modifies the request context. #### Response Example N/A (Middleware modifies context, does not directly respond) ### Initialization Configuration #### Parameters - **initConfig** (PartialConfig) - Optional - `{}` - Explicit configuration object. Overrides environment variables. ### Context Variables Set - **c.var.auth0** (Auth0Context) — User, session, and organization data - **c.var.auth0Client** (ServerClient) — Internal OIDC client instance - **c.var.auth0Configuration** (Configuration) — Parsed configuration - **c.var.__auth0_state_store** (StateStore) — Session persistence store - **c.var.__auth0_session_cache** (SessionData | null) — Request-scoped session cache ### Behavior 1. **Lazy singleton initialization**: OIDC client is initialized once from the first request's environment. 2. **Built-in route mounting**: Automatically handles `/auth/login`, `/auth/callback`, `/auth/logout`, and `/auth/backchannel-logout`. 3. **Eager session loading**: Parses, decrypts, and caches the session cookie on every request. 4. **Context population**: Populates `c.var.auth0` with user, session, and org data. 5. **Optional auth enforcement**: If `authRequired: true` in configuration, applies `requiresAuth()` automatically. ``` -------------------------------- ### Configure Multi-Tenant Setup with Per-Tenant Config Source: https://github.com/auth0-lab/auth0-hono/blob/main/_autodocs/api-reference/handlers.md Illustrates a multi-tenant setup where environment-specific configurations, like tenant IDs, can be used to override Auth0 settings for individual tenants. This requires custom environment binding logic. ```typescript app.get('/login', (c, next) => { const tenantId = c.req.header('x-tenant-id') // Override environment for this tenant // (requires custom env binding logic per runtime) return handleLogin({ forwardAuthorizationParams: ['tenant', 'organization'], })(c, next) }) ``` -------------------------------- ### onCallback Hook Example Source: https://github.com/auth0-lab/auth0-hono/blob/main/_autodocs/api-reference/handlers.md An example of the onCallback hook, demonstrating how to handle both error and success paths during the authentication process. It shows how to enrich the session with custom data on success or redirect on error. ```typescript async function onCallback(c, error, session) { if (error) { // Error path: error is Auth0Error, session is null return c.redirect('/login?error=true') } // Success path: error is null, session is populated const enriched = { ...session, roles: await fetchUserRoles(session.user.sub), } return enriched // Persist enriched session } ``` -------------------------------- ### Basic Auth0 Middleware Setup Source: https://github.com/auth0-lab/auth0-hono/blob/main/_autodocs/INDEX.md Register the auth0() middleware globally and use requiresAuth() for protected routes. Access user details from c.var.auth0.user. ```typescript import { Hono } from 'hono' import { auth0, requiresAuth } from '@auth0/auth0-hono' const app = new Hono() app.use('*', auth0()) // Register on all routes app.get('/', (c) => c.text('Home')) app.get('/protected', requiresAuth(), (c) => { const user = c.var.auth0.user return c.json(user) }) ``` -------------------------------- ### Explicit Configuration without Environment Variables Source: https://github.com/auth0-lab/auth0-hono/blob/main/_autodocs/configuration.md This example demonstrates how to provide all configuration options directly within the `auth0()` middleware function. This is useful when environment variables are not preferred or available. ```typescript app.use('*', auth0({ domain: 'tenant.auth0.com', clientID: 'abc123', clientSecret: 'secret123', baseURL: 'https://myapp.com', session: { secret: 'your_32_character_encryption_key_here', }, })) ``` -------------------------------- ### Getting Access Token for a Specific Connection Source: https://github.com/auth0-lab/auth0-hono/blob/main/_autodocs/types.md Example of using `getAccessTokenForConnection(c)` to obtain an access token for a specified connection, such as 'google-oauth2', optionally providing a login hint for account disambiguation. ```typescript const token = await getAccessTokenForConnection(c, { connection: 'google-oauth2', loginHint: 'user@gmail.com', }) ``` -------------------------------- ### Access Google Drive Files Source: https://github.com/auth0-lab/auth0-hono/blob/main/_autodocs/api-reference/helpers.md Example of using getAccessTokenForConnection to fetch files from Google Drive. It includes error handling for ConnectionTokenError. ```typescript app.get('/sync-google-drive', requiresAuth(), async (c) => { try { const googleToken = await getAccessTokenForConnection(c, { connection: 'google-oauth2', }) const response = await fetch('https://www.googleapis.com/drive/v3/files', { headers: { Authorization: `Bearer ${googleToken.accessToken}` }, }) const files = await response.json() return c.json(files) } catch (err) { if (err instanceof ConnectionTokenError) { return c.json({ error: 'Failed to access Google Drive' }, 401) } throw err } }) ``` -------------------------------- ### Example: Store User Preferences Source: https://github.com/auth0-lab/auth0-hono/blob/main/_autodocs/api-reference/helpers.md Demonstrates how to use `updateSession` to store user-specific preferences like theme and language. The updated session data is available to subsequent handlers. ```typescript app.post('/preferences', requiresAuth(), async (c) => { const { theme, language } = await c.req.json() await updateSession(c, { preferences: { theme, language }, lastUpdated: new Date().toISOString(), }) // Updated session available to subsequent handlers const session = await getSession(c) console.log(session.preferences) // { theme, language } return c.json({ message: 'Preferences saved' }) }) ``` -------------------------------- ### Extracting User Profile Information Source: https://github.com/auth0-lab/auth0-hono/blob/main/_autodocs/types.md Example showing how to extract and use various properties from the `Auth0User` object to construct a profile object. ```typescript const user = c.var.auth0.user if (user) { const profile = { id: user.sub, name: user.name, email: user.email, verified: user.email_verified, organization: user.org_id, customField: user['custom:field'], } } ``` -------------------------------- ### Accessing Session Data and Tokens Source: https://github.com/auth0-lab/auth0-hono/blob/main/_autodocs/types.md Example demonstrating how to retrieve session data using `getSession` and access user email, ID token, and access token. ```typescript const session = await getSession(c) if (session) { console.log(session.user.email) console.log(session.idToken) console.log(session.tokenSets[0].accessToken) console.log(session.permissions) } ``` -------------------------------- ### Basic Standalone Callback Route Source: https://github.com/auth0-lab/auth0-hono/blob/main/_autodocs/api-reference/handlers.md A basic example of setting up a standalone callback route using the handleCallback middleware. This route will handle the OIDC callback from Auth0. ```typescript app.get('/callback', handleCallback()) ``` -------------------------------- ### Basic Auth0 Middleware Setup in Hono Source: https://github.com/auth0-lab/auth0-hono/blob/main/_autodocs/api-reference/auth0-middleware.md Register the auth0 middleware on all routes for basic authentication. Use requiresAuth() for protected routes. ```typescript import { Hono } from 'hono' import { auth0, requiresAuth } from '@auth0/auth0-hono' const app = new Hono() // Register auth middleware on all routes app.use('*', auth0()) // Public route — no authentication required app.get('/', (c) => c.text('Home')) // Protected route — authentication required app.get('/profile', requiresAuth(), (c) => { const user = c.var.auth0.user return c.json({ name: user?.name, email: user?.email }) }) ``` -------------------------------- ### Token Deduplication Example Source: https://github.com/auth0-lab/auth0-hono/blob/main/_autodocs/api-reference/helpers.md Illustrates the promise-based deduplication mechanism of getAccessToken, showing how concurrent requests for a refresh are handled by a single refresh operation. ```typescript // Multiple concurrent requests Promise.all([ getAccessToken(c), // Initiates refresh getAccessToken(c), // Awaits same promise getAccessToken(c), // Awaits same promise getAccessToken(c), // Awaits same promise getAccessToken(c), // Awaits same promise ]) // Only 1 token refresh request sent to Auth0 ``` -------------------------------- ### Basic Auth0 Middleware Setup Source: https://github.com/auth0-lab/auth0-hono/blob/main/README.md Apply the main `auth0()` middleware to handle authentication, session management, and context population for all routes. This middleware automatically sets up login, callback, and logout routes. ```typescript app.use('*', auth0()) ``` -------------------------------- ### Accessing Auth0 Context in Hono Source: https://github.com/auth0-lab/auth0-hono/blob/main/_autodocs/types.md Example demonstrating how to use the `auth0()` middleware and access the populated `c.var.auth0` context within a Hono route. ```typescript app.use('*', auth0()) app.get('/context-demo', (c) => { const { user, session, org } = c.var.auth0 return c.json({ isAuthenticated: user !== null, userName: user?.name, orgId: org?.id, hasTokens: session?.idToken !== undefined, }) }) ``` -------------------------------- ### Handle Unauthenticated Requests with getUser Source: https://github.com/auth0-lab/auth0-hono/blob/main/_autodocs/api-reference/helpers.md Example demonstrating how to use a try-catch block with `getUser(c)` to handle both authenticated and unauthenticated requests gracefully. It specifically catches `MissingSessionError` to provide a guest response. ```typescript app.get('/optional', (c) => { try { const user = getUser(c) return c.json({ message: `Welcome ${user.name}` }) } catch (err) { if (err instanceof MissingSessionError) { return c.json({ message: 'Welcome guest' }) } throw err } }) ``` -------------------------------- ### Using and Checking Auth0 Access Token Source: https://github.com/auth0-lab/auth0-hono/blob/main/_autodocs/types.md Example demonstrating how to retrieve an access token using `getAccessToken(c)`, check its expiration, and use it in an API call's Authorization header. Ensure to handle potential token expiration. ```typescript const token = await getAccessToken(c) // Check expiration const now = Date.now() if (token.expiresAt <= now) { console.log('Token expired') } else { console.log(`Token expires in ${token.expiresAt - now}ms`) } // Use in API call const response = await fetch('https://api.example.com/data', { headers: { Authorization: `Bearer ${token.accessToken}` }, }) ``` -------------------------------- ### Accessing Organization ID and Name Source: https://github.com/auth0-lab/auth0-hono/blob/main/_autodocs/types.md Example of how to access and log the organization ID and name from the `auth0.org` context variable. This context is available after the `auth0()` middleware has been applied. ```typescript const org = c.var.auth0.org if (org) { console.log(org.id) // 'org_abc123' console.log(org.name) // 'Acme Corp' } ``` -------------------------------- ### SessionStore Source: https://github.com/auth0-lab/auth0-hono/blob/main/_autodocs/types.md Abstract base class for implementing custom session storage solutions. It defines methods for setting, getting, and deleting session data, including support for backchannel logout. ```APIDOC ## SessionStore Abstract base class for custom session storage. ### Methods | Method | Parameters | Return | Description | |---|---|---|---| | set | identifier: string, stateData: StateData, deleteSession: boolean, ctx: Context | Promise | Store or delete session | | get | identifier: string, ctx: Context | Promise | Retrieve session | | delete | identifier: string | Promise | Delete session | | deleteByLogoutToken | claims: LogoutTokenClaims, ctx?: Context | Promise | Delete by logout token (backchannel logout) | ### Example: Database Session Store ```typescript import { SessionStore, StateData } from '@auth0/auth0-hono' class DatabaseSessionStore extends SessionStore { async set(identifier: string, stateData: StateData, deleteSession: boolean, ctx: Context): Promise { if (deleteSession) { await db.sessions.delete(stateData.internal.sid) } else { await db.sessions.upsert(stateData.internal.sid, stateData) } } async get(identifier: string, ctx: Context): Promise { const sessionId = ctx.req.header('x-session-id') return await db.sessions.findById(sessionId) } async delete(identifier: string): Promise { // No-op: deletes are handled via set(..., true) } async deleteByLogoutToken(claims: LogoutTokenClaims, ctx?: Context): Promise { await db.sessions.delete(claims.sub) } } app.use('*', auth0({ session: { secret: '...', store: new DatabaseSessionStore(), }, })) ``` ``` -------------------------------- ### Handling ConnectionTokenError in a Route Source: https://github.com/auth0-lab/auth0-hono/blob/main/_autodocs/errors.md Example demonstrating how to catch and handle ConnectionTokenError in a route. This is useful when an operation requiring a connection-specific token fails, prompting the user to re-authorize. ```typescript import { ConnectionTokenError } from '@auth0/auth0-hono' app.get('/sync-google-drive', requiresAuth(), async (c) => { try { const token = await getAccessTokenForConnection(c, { connection: 'google-oauth2', }) // Use token with Google API... } catch (err) { if (err instanceof ConnectionTokenError) { return c.json({ error: 'Failed to access Google Drive. Please reconnect your Google account.' }, 401) } throw err } }) ``` -------------------------------- ### Quick Start: Basic Hono App with Auth0 Middleware Source: https://github.com/auth0-lab/auth0-hono/blob/main/README.md Integrate Auth0 authentication into a Hono application by adding the `auth0()` middleware to all routes and using `requiresAuth()` for protected routes. User information is available via `c.var.auth0.user`. ```typescript import { Hono } from 'hono' import { auth0, requiresAuth } from '@auth0/auth0-hono' const app = new Hono() // Add auth to every route app.use('*', auth0()) // Public route app.get('/', (c) => c.text('Home')) // Protected route app.get('/profile', requiresAuth(), (c) => { const user = c.var.auth0.user return c.json({ name: user?.name, sub: user?.sub }) }) export default app ``` -------------------------------- ### API Call with Access Token Source: https://github.com/auth0-lab/auth0-hono/blob/main/_autodocs/api-reference/helpers.md Example of how to use getAccessToken to fetch data from an external API, including setting the Authorization header with the retrieved access token and handling potential InvalidGrantError. ```typescript app.get('/api/data', requiresAuth(), async (c) => { try { const token = await getAccessToken(c) const response = await fetch('https://api.example.com/data', { headers: { Authorization: `Bearer ${token.accessToken}` }, }) const data = await response.json() return c.json(data) } catch (err) { if (err instanceof InvalidGrantError) { return c.json({ error: 'Token expired, please log in again' }, 401) } throw err } }) ``` -------------------------------- ### Using OIDCEnv in Hono Route Source: https://github.com/auth0-lab/auth0-hono/blob/main/_autodocs/types.md Example of a Hono route handler using `Context` to ensure `c.var.auth0` is fully typed and available. This guarantees that Auth0 context is present after the `auth0()` middleware. ```typescript app.get('/protected', (c: Context) => { // c.var.auth0 is fully typed and required (guaranteed by middleware) // c.var.auth0Client and auth0Configuration are also available return c.json(c.var.auth0.user) }) ``` -------------------------------- ### Route-Level Error Handling Example Source: https://github.com/auth0-lab/auth0-hono/blob/main/_autodocs/errors.md Demonstrates route-level error handling where errors are caught and then re-thrown to be handled by the global error handler. This pattern allows for route-specific logic before global processing. ```typescript app.get('/api/protected', requiresAuth(), async (c) => { try { const token = await getAccessToken(c) // Use token... return c.json({ data: 'success' }) } catch (err) { // Re-throw so global handler catches it throw err } }) ``` -------------------------------- ### Global Error Handler Setup Source: https://github.com/auth0-lab/auth0-hono/blob/main/_autodocs/errors.md Sets up a global error handler for the Hono application to manage various Auth0-specific errors and general exceptions. This ensures consistent error responses across the application. ```typescript import { Auth0Error, LoginRequiredError, AccessDeniedError, InvalidGrantError, MissingSessionError, TokenRefreshError, ConnectionTokenError, } from '@auth0/auth0-hono' app.onError((err, c) => { // Specific Auth0 error types if (err instanceof LoginRequiredError) { return c.json({ error: 'Authentication required' }, 401) } if (err instanceof AccessDeniedError) { return c.json({ error: 'Access denied', code: err.code }, 403) } if (err instanceof InvalidGrantError) { return c.json({ error: 'Token expired, please log in again' }, 401) } if (err instanceof MissingSessionError) { return c.json({ error: 'Session required' }, 401) } if (err instanceof TokenRefreshError) { return c.json({ error: 'Service temporarily unavailable' }, 503) } if (err instanceof ConnectionTokenError) { return c.json({ error: 'Failed to access external service' }, 401) } // Base Auth0Error (catch-all for unmapped errors) if (err instanceof Auth0Error) { return c.json( { error: err.code, error_description: err.description }, err.status ) } // Non-Auth0 errors console.error('Unexpected error:', err) return c.json({ error: 'Internal server error' }, 500) }) ``` -------------------------------- ### Custom Session Store Implementation Source: https://github.com/auth0-lab/auth0-hono/blob/main/README.md Implement a custom session store to manage large session data, preventing issues with overly large session cookies. Ensure your store includes methods for setting, getting, and deleting session data. ```typescript import { SessionStore } from '@auth0/auth0-hono' const customStore: SessionStore = { async set(name, data, isTransaction, ctx) { // Store session data in your database await db.sessions.set(data.internal.sid, data) }, async get(name, ctx) { // Retrieve from database return await db.sessions.get(sessionId) }, // ... delete, clear } app.use('*', auth0({ session: { secret: '...', store: customStore } })) ``` -------------------------------- ### Example: Session Enrichment in Route Handler Source: https://github.com/auth0-lab/auth0-hono/blob/main/_autodocs/api-reference/helpers.md Shows how to update session data within a route handler after performing an action, such as promoting a user to an admin role. This ensures the session reflects the latest user status if the logged-in user is the one being modified. ```typescript app.post('/admin/user/:id/promote', requiresAuth(), async (c) => { const userId = c.req.param('id') // Promote user in database await db.users.updateRole(userId, 'admin') // Update session if this is the logged-in user const currentUser = getUser(c) if (currentUser.sub === userId) { await updateSession(c, { roles: ['admin', 'user'], lastPromoted: new Date().toISOString(), }) } return c.json({ message: 'User promoted' }) }) ``` -------------------------------- ### Sample .env File Configuration Source: https://github.com/auth0-lab/auth0-hono/blob/main/_autodocs/configuration.md Provides a sample .env file illustrating the required and optional environment variables for configuring the Auth0 Hono integration. ```dotenv AUTH0_DOMAIN=tenant.auth0.com AUTH0_CLIENT_ID=abc123xyz AUTH0_CLIENT_SECRET=secret_xyz_ AUTH0_SESSION_ENCRYPTION_KEY=your_32_character_encryption_key_here APP_BASE_URL=https://myapp.com AUTH0_AUDIENCE=https://api.myapp.com ``` -------------------------------- ### Get Access Token for Specific Connection Source: https://github.com/auth0-lab/auth0-hono/blob/main/README.md Use `getAccessTokenForConnection(c, options)` to get a token for service-to-service communication with a specific connection, like Google OAuth2. Requires specifying the `connection` and optionally `loginHint`. ```typescript const token = await getAccessTokenForConnection(c, { connection: 'google-oauth2', loginHint: 'user@example.com' }) ``` -------------------------------- ### Standalone Logout Route Source: https://github.com/auth0-lab/auth0-hono/blob/main/_autodocs/api-reference/handlers.md Use handleLogout to clear the user's session. This handler can be mounted on a GET route. ```typescript app.get('/logout', handleLogout()) ``` -------------------------------- ### Minimal Configuration using Environment Variables Source: https://github.com/auth0-lab/auth0-hono/blob/main/_autodocs/configuration.md This configuration relies entirely on environment variables for all settings. Ensure that AUTH0_DOMAIN, AUTH0_CLIENT_ID, AUTH0_CLIENT_SECRET, AUTH0_SESSION_ENCRYPTION_KEY, and APP_BASE_URL are set in your environment. ```bash AUTH0_DOMAIN=tenant.auth0.com AUTH0_CLIENT_ID=abc123 AUTH0_CLIENT_SECRET=secret123 AUTH0_SESSION_ENCRYPTION_KEY=very_long_string_with_at_least_32_characters APP_BASE_URL=https://myapp.com ``` ```typescript import { auth0 } from '@auth0/auth0-hono' app.use('*', auth0()) // No config parameter needed ``` -------------------------------- ### Full Configuration Object Structure Source: https://github.com/auth0-lab/auth0-hono/blob/main/_autodocs/configuration.md Illustrates the complete structure of the configuration object that can be passed to the auth0() middleware to override environment variables or provide additional options. ```typescript interface PartialConfig { // Core OIDC configuration domain?: string clientID?: string clientSecret?: string baseURL?: string // Session configuration session?: { secret: string | string[] // REQUIRED if not in env var rolling?: boolean // Default: true absoluteDuration?: number // Default: 259200 (3 days) inactivityDuration?: number // Default: 86400 (1 day) store?: SessionStore // Custom session store cookie?: { name?: string // Default: 'appSession' domain?: string sameSite?: 'lax' | 'strict' | 'none' // Default: 'lax' secure?: boolean // Default: auto from baseURL } } // OIDC request parameters authorizationParams?: { scope?: string // Default: 'openid profile email' audience?: string response_type?: string response_mode?: string [key: string]: any } // Forward parameters from query string to authorization request forwardAuthorizationParams?: string[] // Additional token endpoint parameters tokenEndpointParams?: Record // Route configuration routes?: { login?: string // Default: '/auth/login' callback?: string // Default: '/auth/callback' logout?: string // Default: '/auth/logout' backchannelLogout?: string // Default: '/auth/backchannel-logout' } // Custom route override customRoutes?: (keyof Routes)[] // Routes NOT to mount // Mount routes automatically mountRoutes?: boolean // Default: true // Authentication requirements authRequired?: boolean // Default: false (recommended: explicitly set per route) // Logout behavior idpLogout?: boolean // Default: false (logout from Auth0) // OIDC client options pushedAuthorizationRequests?: boolean // Default: false (PAR flow) clockTolerance?: number // Default: 60 (seconds) enableTelemetry?: boolean // Default: true httpTimeout?: number // Default: 5000 (milliseconds) // Callback hooks onCallback?: (c, error, session) => Promise } ``` -------------------------------- ### Handle MissingSessionError in Profile Route Source: https://github.com/auth0-lab/auth0-hono/blob/main/_autodocs/errors.md Example of handling MissingSessionError when fetching user profile data. If the error occurs, it prompts the user to log in. ```typescript import { MissingSessionError, getUser } from '@auth0/auth0-hono' app.get('/profile', (c) => { try { const user = getUser(c) return c.json(user) } catch (err) { if (err instanceof MissingSessionError) { return c.json({ error: 'Please log in' }, 401) } throw err } }) ``` -------------------------------- ### Handle InvalidGrantError in API Route Source: https://github.com/auth0-lab/auth0-hono/blob/main/_autodocs/errors.md Example of handling InvalidGrantError within an API route. If the error occurs, it suggests the user needs to log in again. ```typescript import { InvalidGrantError } from '@auth0/auth0-hono' app.get('/api/data', requiresAuth(), async (c) => { try { const token = await getAccessToken(c) // Use token... } catch (err) { if (err instanceof InvalidGrantError) { return c.json({ error: 'Token expired, please log in again' }, 401) } throw err } }) ``` -------------------------------- ### Initialize Standalone Login, Callback, and Logout Handlers Source: https://github.com/auth0-lab/auth0-hono/blob/main/_autodocs/api-reference/handlers.md Demonstrates how to use standalone handlers for login, callback, and logout routes in a Hono application. Ensure these handlers are imported from '@auth0/auth0-hono'. ```typescript import { Hono } from 'hono' import { handleLogin, handleCallback, handleLogout } from '@auth0/auth0-hono' const app = new Hono() // Use standalone handlers instead of auth0() middleware app.get('/login', handleLogin()) app.get('/callback', handleCallback()) app.get('/logout', handleLogout()) export default app ``` -------------------------------- ### Type-Safe Handler After requiresAuth Source: https://github.com/auth0-lab/auth0-hono/blob/main/_autodocs/api-reference/protection-middleware.md After `requiresAuth()` is successfully executed, `c.var.auth0.user` is guaranteed to be defined. This example demonstrates type-safe access to user data within a handler. ```typescript import { OIDCEnv } from '@auth0/auth0-hono' app.get('/protected', requiresAuth(), (c: Context) => { // c.var.auth0.user is guaranteed to be defined here return c.json(c.var.auth0.user) }) ``` -------------------------------- ### Handle MissingTransactionError Globally Source: https://github.com/auth0-lab/auth0-hono/blob/main/_autodocs/errors.md Example of handling MissingTransactionError using a global error handler. If the error occurs, the user is redirected to the login page to restart the process. ```typescript import { MissingTransactionError } from '@auth0/auth0-hono' app.onError((err, c) => { if (err instanceof MissingTransactionError) { return c.redirect('/login?error=invalid_callback') } }) ``` -------------------------------- ### Development Configuration Source: https://github.com/auth0-lab/auth0-hono/blob/main/_autodocs/configuration.md Configure Auth0 middleware for local development. Ensure `secure` is false for HTTP connections. ```typescript app.use('*', auth0({ domain: 'tenant.auth0.com', clientID: 'dev_client_id', clientSecret: 'dev_secret', baseURL: 'http://localhost:3000', session: { secret: 'dev_encryption_key_32_characters_minimum', cookie: { secure: false, // Allow http://localhost }, }, })) ``` -------------------------------- ### Get Access Token for API Calls Source: https://github.com/auth0-lab/auth0-hono/blob/main/_autodocs/INDEX.md Use getAccessToken() within a protected route to fetch an access token. This token can be used to authenticate with external APIs. ```typescript import { getAccessToken } from '@auth0/auth0-hono' app.get('/api/data', requiresAuth(), async (c) => { const { accessToken } = await getAccessToken(c) const response = await fetch('https://api.example.com/data', { headers: { Authorization: `Bearer ${accessToken}` }, }) return c.json(await response.json()) }) ``` -------------------------------- ### Middleware Composition and Error Handling Source: https://github.com/auth0-lab/auth0-hono/blob/main/_autodocs/api-reference/protection-middleware.md Demonstrates how to chain multiple middleware functions for layered security and how to implement a global error handler for Auth0-specific errors. ```APIDOC ## Middleware Composition Middleware can be composed in route chains. Authorization checks should follow authentication. ```typescript app.get('/dashboard', requiresAuth(), // 1. Check authenticated requiresOrg(), // 2. Check has organization claimEquals('role', 'admin'), // 3. Check role (c) => c.json({ data: 'admin dashboard' }) ) ``` All middleware in the chain must pass for the handler to execute. If any middleware throws an error, the error handler takes over. ## Error Handling ```typescript import { Auth0Error, AccessDeniedError } from '@auth0/auth0-hono' app.onError((err, c) => { if (err instanceof AccessDeniedError) { return c.json({ error: 'Access denied' }, 403) } if (err instanceof Auth0Error) { return c.json({ error: err.code }, err.status) } return c.json({ error: 'Server error' }, 500) }) ``` ``` -------------------------------- ### auth0 Middleware with Explicit Configuration Source: https://github.com/auth0-lab/auth0-hono/blob/main/_autodocs/api-reference/auth0-middleware.md This snippet demonstrates how to provide explicit configuration options to the Auth0 middleware, overriding environment variables for more control. ```APIDOC ## auth0 Middleware with Explicit Configuration ### Description Provides explicit configuration to the `auth0()` middleware, allowing you to override default settings and environment variables. This is useful for specifying custom domains, client IDs, secrets, session configurations, and authorization parameters. ### Method `app.use()` ### Endpoint `*` (all routes) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```typescript app.use( '*', auth0({ domain: 'tenant.auth0.com', clientID: 'abc123xyz', clientSecret: 'secret_xyz', baseURL: 'https://myapp.com', session: { secret: 'your_32_character_encryption_key', cookie: { name: 'auth_session', sameSite: 'lax', secure: true, }, }, authorizationParams: { scope: 'openid profile email', audience: 'https://api.myapp.com', }, }) ) ``` ### Response #### Success Response (200) N/A (Middleware modifies context, does not directly respond) #### Response Example N/A ``` -------------------------------- ### Handling AccessDeniedError in Hono Source: https://github.com/auth0-lab/auth0-hono/blob/main/_autodocs/errors.md Example of handling AccessDeniedError in a Hono application's onError handler. This snippet returns a 403 JSON response with the specific error code. ```typescript import { AccessDeniedError } from '@auth0/auth0-hono' app.onError((err, c) => { if (err instanceof AccessDeniedError) { return c.json({ error: 'Access denied', code: err.code }, 403) } }) ``` -------------------------------- ### Handling TokenRefreshError in a Route Source: https://github.com/auth0-lab/auth0-hono/blob/main/_autodocs/errors.md Example of how to catch and handle TokenRefreshError within an application route. This demonstrates differentiating between transient errors like TokenRefreshError and non-retriable errors like InvalidGrantError. ```typescript import { TokenRefreshError } from '@auth0/auth0-hono' app.get('/api/data', requiresAuth(), async (c) => { try { const token = await getAccessToken(c) // Use token... } catch (err) { if (err instanceof TokenRefreshError) { // Transient error — might succeed on retry return c.json({ error: 'Temporary service error' }, 503) } if (err instanceof InvalidGrantError) { // Token invalid — requires re-login return c.json({ error: 'Please log in again' }, 401) } throw err } }) ``` -------------------------------- ### Multi-Tenant Configuration with Standalone Handlers Source: https://github.com/auth0-lab/auth0-hono/blob/main/_autodocs/configuration.md For multi-tenant deployments, use standalone handlers instead of the auth0() middleware. Each handler reads environment variables per-request, allowing for different Auth0 credentials per tenant. ```typescript // Don't use auth0() middleware — use standalone handlers instead app.get('/login', handleLogin()) app.get('/callback', handleCallback()) app.get('/logout', handleLogout()) app.post('/backchannel-logout', handleBackchannelLogout()) ``` -------------------------------- ### Handling LoginRequiredError in Hono Source: https://github.com/auth0-lab/auth0-hono/blob/main/_autodocs/errors.md Example of handling LoginRequiredError in a Hono application's onError handler. This snippet shows how to return a 401 response or redirect the user to a login page. ```typescript import { LoginRequiredError } from '@auth0/auth0-hono' app.onError((err, c) => { if (err instanceof LoginRequiredError) { // Redirect to login or return 401 return c.json({ error: 'Authentication required' }, 401) } }) ``` -------------------------------- ### Mount Default Auth0 Routes Source: https://github.com/auth0-lab/auth0-hono/blob/main/_autodocs/configuration.md Mount all default Auth0 routes automatically. This is the recommended approach for most applications. ```typescript app.use('*', auth0({ mountRoutes: true, // Default — mounts all 4 routes })) ``` -------------------------------- ### Environment Variables for Auth0 Configuration Source: https://github.com/auth0-lab/auth0-hono/blob/main/README.md Configure the Auth0 SDK by setting environment variables. These variables define your Auth0 domain, client ID, and application base URL, among other settings. ```dotenv AUTH0_DOMAIN=tenant.auth0.com AUTH0_CLIENT_ID=abc123 AUTH0_CLIENT_SECRET=secret123 AUTH0_SESSION_ENCRYPTION_KEY=very_long_string_with_at_least_32_characters APP_BASE_URL=https://myapp.com ``` -------------------------------- ### Get Access Token for Connection Source: https://github.com/auth0-lab/auth0-hono/blob/main/_autodocs/api-reference/helpers.md Retrieves an access token for a specific social provider connection. Use this when your application needs to access resources on a third-party service on behalf of the user. ```typescript async function getAccessTokenForConnection( c: Context, options: GetAccessTokenForConnectionOptions ): Promise ``` -------------------------------- ### Main Middleware Source: https://github.com/auth0-lab/auth0-hono/blob/main/_autodocs/INDEX.md The `auth0(config?)` function is the primary middleware for setting up OIDC authentication. It supports configuration precedence, a lazy singleton pattern, and the `onCallback` hook for session enrichment. ```APIDOC ## auth0(config?) ### Description Provides the main OIDC authentication middleware for Hono applications. It manages authentication flows, session management, and integrates with Auth0. ### Method Middleware (typically used with Hono's `app.use()`) ### Endpoint N/A (Middleware) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Configuration Options (Optional `config` object) - **domain** (string): Your Auth0 domain (e.g., 'your-tenant.auth0.com'). - **clientID**: Your Auth0 application's Client ID. - **clientSecret**: Your Auth0 application's Client Secret. - **issuerBaseURL**: The base URL of the issuer (e.g., `https://${domain}`). - **authorizationParams**: Parameters to include in the authorization request. - **session**: Session configuration object. - **cookie**: Cookie configuration. - **store**: Custom session store implementation. - **rolling**: Whether to roll the session expiration on each request. - **absoluteDuration**: The absolute duration of the session in seconds. - **slidingDuration**: The sliding duration of the session in seconds. - **onCallback**: A hook function to enrich the session after a successful callback. - `async onCallback(app: Hono, session: Auth0Session, state: Record) => Promise` ### Request Example ```javascript import { Hono } from 'hono'; import { auth0 } from '@auth0/auth0-hono'; const app = new Hono(); app.use(auth0({ domain: process.env.AUTH0_DOMAIN, clientID: process.env.AUTH0_CLIENT_ID, clientSecret: process.env.AUTH0_CLIENT_SECRET, onCallback: async (app, session, state) => { // Enrich session with custom data session.user.customData = 'someValue'; } })); // ... other routes ``` ### Response #### Success Response Middleware processes the request and may modify the context or redirect the user. #### Response Example N/A (Middleware) ``` -------------------------------- ### Custom Database Session Store Source: https://github.com/auth0-lab/auth0-hono/blob/main/_autodocs/configuration.md Integrate a custom session store, such as a database, by extending the `SessionStore` class and implementing its methods. ```typescript import { SessionStore } from '@auth0/auth0-hono' class DatabaseSessionStore extends SessionStore { async set(identifier, stateData, deleteSession, ctx) { if (deleteSession) { await db.sessions.delete(stateData.internal.sid) } else { await db.sessions.upsert(stateData.internal.sid, stateData) } } async get(identifier, ctx) { return await db.sessions.get(identifier) } async delete(identifier) { // Handled by set(..., true) } async deleteByLogoutToken(claims, ctx) { // Backchannel logout support await db.sessions.delete(claims.sub) } } app.use('*', auth0({ session: { secret: 'encryption_key', store: new DatabaseSessionStore(), }, })) ``` -------------------------------- ### SessionStore Abstract Class Definition Source: https://github.com/auth0-lab/auth0-hono/blob/main/_autodocs/types.md Defines the abstract methods required for a custom session store. Implementations must provide logic for setting, getting, and deleting session data. ```typescript abstract class SessionStore { abstract delete(identifier: string): Promise abstract set(identifier: string, stateData: StateData): Promise abstract get(identifier: string): Promise abstract deleteByLogoutToken(claims: LogoutTokenClaims, c?: Context | undefined): Promise } ``` -------------------------------- ### auth0(config?) Source: https://github.com/auth0-lab/auth0-hono/blob/main/README.md The main middleware for the Auth0 Hono SDK. It sets up login, callback, and logout routes, handles session management, encrypts session cookies, and populates user data on the request context. It also manages transparent and deduplicated token refreshes. ```APIDOC ## auth0(config?) ### Description Main middleware — sets up routes, session management, and context population. ### Method ``` app.use('*', auth0()) ``` ### What it handles automatically: - Login/callback/logout routes (`/auth/login`, `/auth/callback`, `/auth/logout`) - Backchannel logout - Session encryption and cookie management - User data available on every request via `c.var.auth0.user` - Token refresh (transparent, deduplicated) ### Options: ```typescript { domain?: string // Auth0 domain clientID?: string // Client ID clientSecret?: string // Client secret baseURL?: string // App base URL session?: { secret: string | string[] // Encryption key(s) — supports rotation cookie?: { name?: string // Default: 'appSession' domain?: string sameSite?: 'lax' | 'strict' | 'none' secure?: boolean } store?: SessionStore // Custom session store (optional) } authorizationParams?: Record // Scope, audience, etc. routes?: { login?: string // Default: '/auth/login' callback?: string // Default: '/auth/callback' logout?: string // Default: '/auth/logout' backchannelLogout?: string // Default: '/auth/backchannel-logout' } onCallback?: (c, error, session) => ... // Post-login hook (see Hooks below) attemptSilentLogin?: boolean // Default: false fetch?: typeof global.fetch // Custom fetch (optional) } ``` ``` -------------------------------- ### Get Authenticated User Source: https://github.com/auth0-lab/auth0-hono/blob/main/README.md Use `getUser(c)` to retrieve the authenticated user object. This function throws a `MissingSessionError` if the user is not authenticated. Access user properties like `name` directly. ```typescript const user = getUser(c) console.log(user.name) ``` -------------------------------- ### Get Authenticated User Synchronously Source: https://github.com/auth0-lab/auth0-hono/blob/main/_autodocs/api-reference/helpers.md Synchronously retrieve the authenticated user object. This function is intended for use in handlers that have already enforced authentication with `requiresAuth()`, as it throws an error if no session is found. ```typescript function getUser(c: Context): Auth0User ``` -------------------------------- ### Mount Standalone Authentication Handlers Source: https://github.com/auth0-lab/auth0-hono/blob/main/README.md Mount authentication handlers like `handleLogin`, `handleLogout`, `handleCallback`, and `handleBackchannelLogout` on custom routes without needing the main `auth0()` middleware. Configuration is resolved from environment variables. ```typescript import { handleLogin, handleLogout, handleCallback, handleBackchannelLogout } from '@auth0/auth0-hono' // Mount handlers on custom routes app.get('/login', handleLogin()) app.get('/logout', handleLogout()) app.get('/callback', handleCallback()) app.post('/logout-notify', handleBackchannelLogout()) ``` -------------------------------- ### Session Key Rotation Configuration Source: https://github.com/auth0-lab/auth0-hono/blob/main/_autodocs/types.md Illustrates how to configure session secrets using an array of keys for rotation. The first key is used for encrypting new sessions, while subsequent keys are for decrypting existing ones. ```typescript session: { secret: [ 'new_key_generated_today', // Current key (encrypts) 'previous_key_from_last_month', // Old key (decrypts only) 'very_old_key_from_three_months_ago', // Older key (decrypts only) ], } ``` -------------------------------- ### Production Configuration with Advanced Settings Source: https://github.com/auth0-lab/auth0-hono/blob/main/_autodocs/configuration.md This production configuration includes detailed session management, custom cookie settings, and specific authorization parameters. It also enables global logout via `idpLogout` and disables telemetry. ```typescript app.use('*', auth0({ domain: 'tenant.auth0.com', clientID: process.env.AUTH0_CLIENT_ID, clientSecret: process.env.AUTH0_CLIENT_SECRET, baseURL: 'https://myapp.com', session: { secret: process.env.AUTH0_SESSION_ENCRYPTION_KEY, rolling: true, absoluteDuration: 7 * 24 * 60 * 60, // 7 days inactivityDuration: 60 * 60, // 1 hour cookie: { name: 'auth_session', sameSite: 'lax', secure: true, domain: '.myapp.com', // Shared across subdomains }, }, authorizationParams: { scope: 'openid profile email', audience: 'https://api.myapp.com', }, idpLogout: true, // Logout from Auth0 globally enableTelemetry: false, })) ``` -------------------------------- ### Mixed Configuration with Environment Variables and Overrides Source: https://github.com/auth0-lab/auth0-hono/blob/main/_autodocs/configuration.md This configuration uses environment variables for most settings but allows for specific overrides. It demonstrates how to access environment variables for session secrets and customize cookie attributes and authorization parameters. ```typescript app.use('*', auth0({ // Most settings from env vars, override a few session: { secret: process.env.AUTH0_SESSION_ENCRYPTION_KEY, cookie: { name: 'my_custom_session', sameSite: 'strict', secure: true, }, }, authorizationParams: { audience: 'https://api2.example.com', // Override default audience }, })) ``` -------------------------------- ### Get Access Token Source: https://github.com/auth0-lab/auth0-hono/blob/main/README.md Use `getAccessToken(c)` to obtain an access token, which automatically refreshes if expired. The token audience is configured via `authorizationParams.audience`. Supports token deduplication for parallel requests. ```typescript const { accessToken } = await getAccessToken(c) // Use in API call const res = await fetch('https://api.example.com/data', { headers: { Authorization: `Bearer ${accessToken}` } }) ``` -------------------------------- ### Retrieve Full Session Object Source: https://github.com/auth0-lab/auth0-hono/blob/main/README.md Use `getSession(c)` to get the complete session object. It returns `null` if the user is not authenticated. Access user details like email from the returned session. ```typescript const session = await getSession(c) if (session) { console.log(session.user.email) } ``` -------------------------------- ### Configure Custom Auth0 Route Paths Source: https://github.com/auth0-lab/auth0-hono/blob/main/_autodocs/configuration.md Customize the paths for Auth0's default routes, such as login, callback, and logout, to match your application's structure. ```typescript app.use('*', auth0({ routes: { login: '/login', callback: '/oauth/callback', logout: '/logout', backchannelLogout: '/backchannel', }, })) ``` -------------------------------- ### Cloudflare Workers Environment Variables Configuration Source: https://github.com/auth0-lab/auth0-hono/blob/main/README.md Example configuration for `wrangler.toml` to correctly set environment variables like `AUTH0_DOMAIN` and `AUTH0_CLIENT_ID` for Cloudflare Workers. This ensures the SDK can access necessary Auth0 configuration. ```toml [env.production] vars = { AUTH0_DOMAIN = "tenant.auth0.com", AUTH0_CLIENT_ID = "abc123" } ```