Nuxt Module
The @riavzon/auth-h3client module handles authentication for Nuxt applications. It provides a module that auto-imports client-side composables and server-side utilities, plus optional security middleware.
Requirements
- Node.js 22 or later
- Nuxt 3 and later or a Nitro/H3 application
- A running IAM service reachable from your server
Installation
pnpm add @riavzon/auth-h3client
yarn add @riavzon/auth-h3client
npm install @riavzon/auth-h3client
bun add @riavzon/auth-h3client
Nuxt module setup
Register the module in nuxt.config.ts. This enables the auto-import of all server utilities and client composables, and optionally registers the global security middleware.
export default defineNuxtConfig({
modules: ['auth-h3client/module'],
authH3Client: {
enableMiddleware: true,
authStatusUrl: '/api/auth/users/authStatus',
registerApiRoute: {
path: '/api/auth/api-tokens'
}
}
})
Module options
false if you want to provide your own middleware so you can exclude machine-to-machine routes protected by defineAuthenticatePublicApi. This only disables the bundled middleware. The module still registers the auth status route and any configured registerApiRoute handler."/api/auth/users/authStatus" - The route path for the auth
status endpoint. The module registers a GET handler at this path that returns
the current session state. The useAuthData composable calls this endpoint by
default.getApiListsController. Use this to expose the authenticated API token
inventory to your frontend without manually wiring a route.registerApiRoute is set - The path where the module registers
the API token inventory route. For example, "/api/auth/api-tokens".enableFireWallBans: false in your plugin configuration. The firewall ban feature uses sudo ufw and is only available on Linux servers with UFW installed.Plugin configuration
The module does not configure the library automatically because the configuration includes non-serializable values such as storage instances and callbacks. You must create a Nitro plugin that calls defineAuthConfiguration.
defineAuthConfiguration initializes the library, starts the HTTP request logger, and registers all authentication routes on the Nitro router in one call. This is the recommended setup for Nuxt applications.
Using a config template
The module ships two config templates that read from environment variables, giving you a working baseline with no manual wiring:
| Template | Description |
|---|---|
configDefaults | Core authentication with HMAC signing and unstorage caching |
configDefaultsWithOAuth | Extends configDefaults with Google, GitHub, X, and LinkedIn OAuth providers |
Create a Nitro plugin and spread the template as the base:
import { defineNitroPlugin } from 'nitropack/runtime'
import { useStorage } from 'nitropack/runtime/storage'
import { configDefaults } from 'auth-h3client/server/templates'
import { defineAuthConfiguration } from 'auth-h3client/v1'
export default defineNitroPlugin((nitroApp) => {
defineAuthConfiguration(nitroApp, {
...configDefaults,
onSuccessRedirect: '/dashboard',
uStorage: {
storage: useStorage('cache'),
cacheOptions: {
successTtl: 60 * 60 * 24 * 30,
rateLimitTtl: 10
}
}
})
})
configDefaults reads the following environment variables:
| Variable | Required | Description |
|---|---|---|
AUTH_SERVER_LOCATION | Yes | Hostname or IP address of the IAM service |
AUTH_PORT_LOCATION | Yes | Port the IAM service listens on |
HMAC_CLIENT_ID | No | HMAC client identifier. Auto-generated if omitted |
HMAC_SHARED_SECRET | No | HMAC shared secret. Auto-generated if omitted |
AUTH_CRYPTO_COOKIES | No | Secret used to sign cookies. Auto-generated if omitted |
When using configDefaultsWithOAuth, add the following variables:
| Variable | Required | Description |
|---|---|---|
BASEURL | Yes | Full base URL of your application, e.g. https://app.example.com |
OAUTH_GOOGLE_CLIENT_ID | Yes | Google OAuth client ID |
OAUTH_GOOGLE_CLIENT_SECRET | Yes | Google OAuth client secret |
OAUTH_GITHUB_CLIENT_ID | Yes | GitHub OAuth client ID |
OAUTH_GITHUB_CLIENT_SECRET | Yes | GitHub OAuth client secret |
OAUTH_X_CLIENT_ID | Yes | X (Twitter) OAuth client ID |
OAUTH_X_CLIENT_SECRET | Yes | X (Twitter) OAuth client secret |
OAUTH_LINKEDIN_CLIENT_ID | Yes | LinkedIn OAuth client ID |
OAUTH_LINKEDIN_CLIENT_SECRET | Yes | LinkedIn OAuth client secret |
HMAC_CLIENT_ID, HMAC_SHARED_SECRET, and AUTH_CRYPTO_COOKIES should be stable across restarts and match what the IAM service expects. If you let the template auto-generate them, they will differ on every cold start.Manual configuration
If you need full control over every option, pass the full configuration object directly to defineAuthConfiguration without a template. See the Configuration reference for a description of every field.
import { defineNitroPlugin } from 'nitropack/runtime'
import { useStorage } from 'nitropack/runtime/storage'
import { configDefaults } from 'auth-h3client/server/templates'
import { defineAuthConfiguration } from 'auth-h3client/v1'
export default defineNitroPlugin((nitroApp) => {
defineAuthConfiguration(nitroApp, {
...configDefaults,
// Override individual fields as needed
onSuccessRedirect: '/dashboard',
enableFireWallBans: false,
logLevel: 'info',
htmlSanitizer: {
IrritationCount: 50,
maxAllowedInputLength: 50000
},
imageUploader: {
allowedBytes: 5_000_000,
allowedMimes: ['image/png', 'image/jpeg', 'image/webp'],
allowedExtensions: ['png', 'webp', 'jpeg', 'jpg']
},
uStorage: {
storage: useStorage('cache'),
cacheOptions: {
successTtl: 60 * 60 * 24 * 30,
rateLimitTtl: 10
}
}
})
})
See the Configuration reference for a description of every field.
What the module registers
Global middleware
When enableMiddleware is true, the module registers a single server middleware that runs on every request before your route handlers. It skips HEAD requests, the /api/health path, Nuxt internal paths, and requests forwarded from localhost.
For all other requests it runs three operations in order:
- IP validation: extracts and validates the client IP and visitor fingerprint
- Bot detection: forwards the fingerprint to the IAM service check endpoint and returns 403 if the visitor is flagged
- CSRF cookie: mints a signed
__Host-csrfcookie if one is not already present
defineAuthenticatePublicApi. Those routes handle machine-to-machine
X-API-KEY verification, so running browser middleware on every request can
trigger bot-detector rate limits or bans. Keep the middleware enabled for
regular auth routes, because login, session rotation, MFA,
getApiListsController, and defineApiManagementHandler still depend on bot
detection and the CSRF cookie. In mixed apps, set enableMiddleware: false
and register your own server middleware that skips the API-key routes.Auth status route
The module registers a GET handler at authStatusUrl (default
/api/auth/users/authStatus). This route proxies to the IAM service and
returns the current session state. The useAuthData composable fetches this
route during SSR and on the client.
Optional API token list route
When registerApiRoute is set, the module registers a GET handler at
registerApiRoute.path using getApiListsController. This route returns the
authenticated user's API token inventory and strips each token's
public_identifier before the response reaches the browser.
Authentication routes
defineAuthConfiguration registers the following routes on the Nitro router:
| Method | Path | Description |
|---|---|---|
| POST | /login | Email and password login |
| POST | /signup | User registration |
| POST | /logout | Session termination |
| GET | /oauth/:provider | Initiate an OAuth or OIDC flow |
| GET/POST | /oauth/callback/:provider | OAuth provider callback handler |
| GET | /auth/bounce | Magic link redirect entry point |
| GET | /api/auth/verify-mfa | MFA magic link validation |
| POST | /api/auth/verify-mfa | Submit an MFA code |
| POST | /api/auth/password-reset | Request a password reset link |
| GET | /api/auth/reset-password | Password reset link validation |
| POST | /api/auth/reset-password | Submit a new password |
| POST | /api/auth/change-email | Initiate an email change |
| GET | /api/auth/update-email | Email change link validation |
| POST | /api/auth/update-email | Confirm new email address |
For the full middleware chain and request/response details for each route, see the Routes Reference.
Auto-imported server utilities
All server utilities from auth-h3client/v1 are auto-imported in your server/ directory. You do not need to import them manually inside any server route or plugin.
Auto-imported client composables
The following composables are auto-imported in your Vue components and pages:
| Composable | Description |
|---|---|
useAuthData | Reactive authentication state with SSR hydration |
useMagicLink | Reads and routes magic link query parameters |
executeRequest | Fetch wrapper with CSRF injection and cookie forwarding |
getCsrfToken | Reads the CSRF token from the cookie |
See Client-Side for full details.
Verify the setup
Start your development server and make a request to the auth status endpoint. With no active session the response should be:
curl http://localhost:3000/api/auth/users/authStatus
{
"authorized": false
}
A __Host-csrf cookie should also be present on the response. If the IAM service is unreachable, the auth status handler returns { "authorized": false } rather than erroring, so check the server logs if you expect a different result.
Create a protected endpoint
Try creating a simple endpoint and querying it in your frontend:
// This will only return successful response in the user its authenticate
export default defineAuthenticatedEventHandler(async (event) => {
const user = event.context.authorizedData;
return user;
})
<script setup lang="ts">
import { executeRequest } from '@riavzon/auth-h3client/client';
const result = await executeRequest<Data>(
'/api/protected',
'GET',
{},
{},
{},
{
headers: useRequestHeaders(),
event: useRequestEvent(),
fetcher: useRequestFetch(),
},
)
const data = result.data
</script>
<template>
<div> {{ data }} </div>
</template>