Server Utilities
Server-side utility functions for authentication in API routes and middleware.
Import request handlers and their helpers explicitly from nuxt/server; Nuxt 4 server auto-imports still use h3. Event-taking Aegis utilities accept the portable RequestEvent from nuxt/server.
Authentication Utilities
requireAuth(event)
Require authentication and return the event with a guaranteed authenticated user in its context.
Type Signature:
function requireAuth<T extends BaseTokenClaims = BaseTokenClaims>(
event: RequestEvent,
): RequestEvent & { context: { user: T } }Parameters:
| Parameter | Type | Description |
|---|---|---|
event | RequestEvent | Server request event |
Returns: The same event, with context.user narrowed to T.
Throws: 401 Unauthorized if user is not authenticated or token is invalid/expired
Example:
// server/routes/api/profile.get.ts
import { defineEventHandler } from 'nuxt/server'
export default defineEventHandler((event) => {
// Require authentication (throws 401 if not authenticated)
const { user } = requireAuth(event).context
// User is guaranteed to be authenticated here
return {
profile: {
name: user.name,
email: user.email,
role: user.role,
}
}
})Authentication Required
requireAuth() throws a 401 error if the user is not authenticated. Always handle this gracefully on the client side.
getAuthUser(event)
Optionally get the current user without throwing an error.
Type Signature:
function getAuthUser<T extends BaseTokenClaims = BaseTokenClaims>(event: RequestEvent): T | nullParameters:
| Parameter | Type | Description |
|---|---|---|
event | RequestEvent | Server request event |
Returns: T | null - User object if authenticated, null otherwise
Example:
// server/routes/api/posts.get.ts
import { defineEventHandler } from 'nuxt/server'
export default defineEventHandler(async (event) => {
// Get user if authenticated (doesn't throw)
const user = getAuthUser(event)
if (user) {
// Return personalized content
return await getPersonalizedPosts(user.sub)
}
// Return public content
return await getPublicPosts()
})Token Utilities
generateAuthTokens(event, providerUserInfo, provider, customClaims?)
Generate a JWT access token and, when token refresh is enabled, create and store a refresh token. Call this only after authenticating the user. It does not set the refresh-token cookie.
Type Signature:
async function generateAuthTokens(
event: RequestEvent,
providerUserInfo: Record<string, unknown>,
provider: string,
customClaims?: Record<string, unknown>,
): Promise<{ accessToken: string, refreshToken?: string }>Parameters:
| Parameter | Type | Description |
|---|---|---|
event | RequestEvent | Server request event |
providerUserInfo | Record<string, unknown> | Complete authenticated user data, retained with the refresh token |
provider | string | Provider name, such as google or github |
customClaims | Record<string, unknown> | Optional already-resolved custom claims |
Returns: A token pair. refreshToken is absent when token refresh is disabled. Send only accessToken in the response body; use an HttpOnly cookie for the refresh token.
Example:
// server/utils/createToken.ts
import type { RequestEvent } from 'nuxt/server'
import { generateAuthTokens } from '#nuxt-aegis/server'
export async function createCustomTokens(
event: RequestEvent,
user: Record<string, unknown>,
provider: string,
) {
return await generateAuthTokens(event, user, provider, {
role: user.role,
premium: user.premium,
})
}For request authentication, use requireAuth(event).context.user or nullable getAuthUser(event). JWT verification is performed by the module's authentication middleware; there is no public standalone token-verification utility.
Refresh Token Utilities
hashRefreshToken(token)
Hash a refresh token using SHA-256. Used with revokeRefreshToken() and deleteUserRefreshTokens().
Type Signature:
function hashRefreshToken(token: string): stringParameters:
| Parameter | Type | Description |
|---|---|---|
token | string | Refresh token to hash |
Returns: string - Hashed token as hex string
Example:
// server/routes/admin/revoke-token.post.ts
export default defineEventHandler(async (event) => {
const { refreshToken } = await readBody(event)
const tokenHash = hashRefreshToken(refreshToken)
await revokeRefreshToken(tokenHash)
return { success: true }
})revokeRefreshToken(tokenHash)
Revoke a refresh token by marking it as revoked without deleting it. This preserves the token data for audit purposes while preventing its use.
Type Signature:
async function revokeRefreshToken(
tokenHash: string
): Promise<void>Parameters:
| Parameter | Type | Description |
|---|---|---|
tokenHash | string | Hashed refresh token (use hashRefreshToken()) |
Example:
// server/routes/admin/revoke-session.post.ts
export default defineEventHandler(async (event) => {
const user = await requireAuth(event)
// Check admin permissions
if (user.role !== 'admin') {
throw createError({ status: 403, message: 'Admin access required' })
}
const { refreshToken } = await readBody(event)
const tokenHash = hashRefreshToken(refreshToken)
// Revoke the token (marks as revoked, preserves for audit)
await revokeRefreshToken(tokenHash)
return {
success: true,
message: 'Token revoked successfully'
}
})Audit Trail
Revoked tokens remain in storage with an isRevoked flag, maintaining an audit trail while preventing their use.
deleteUserRefreshTokens(email, exceptTokenHash?)
Delete all refresh tokens for a specific user. Useful for security operations like password changes or account deletion.
Type Signature:
async function deleteUserRefreshTokens(
email: string,
exceptTokenHash?: string
): Promise<void>Parameters:
| Parameter | Type | Description |
|---|---|---|
email | string | User email to match |
exceptTokenHash | string | Optional token hash to preserve (e.g., current session) |
Example:
// server/routes/auth/password/change.post.ts
export default defineEventHandler(async (event) => {
const user = await requireAuth(event)
const { oldPassword, newPassword } = await readBody(event)
// Verify old password and update to new password
await updateUserPassword(user.email, oldPassword, newPassword)
// Get current refresh token hash to preserve current session
const currentRefreshToken = getRefreshTokenFromCookie(event)
const currentTokenHash = currentRefreshToken
? hashRefreshToken(currentRefreshToken)
: undefined
// Revoke all other sessions for security
await deleteUserRefreshTokens(user.email, currentTokenHash)
return {
success: true,
message: 'Password changed, other sessions revoked'
}
})Security Best Practice
Always call deleteUserRefreshTokens() when users change their password or when accounts are deleted to prevent unauthorized access through old refresh tokens.
Cookie Utilities
setRefreshTokenCookie(event, token, cookieConfig?)
Set the refresh token cookie. This helper is available as a server auto-import, not as a named export from #nuxt-aegis/server.
Type Signature:
function setRefreshTokenCookie(
event: RequestEvent,
token: string,
cookieConfig?: CookieConfig,
): voidParameters:
| Parameter | Type | Description |
|---|---|---|
event | RequestEvent | Server request event |
token | string | Refresh token |
cookieConfig | CookieConfig | Optional cookie settings, including maxAge in seconds; pass nuxtAegis.tokenRefresh.cookie to honor module configuration |
Example:
// server/utils/customAuth.ts
import { useRuntimeConfig } from 'nuxt/server'
import type { RequestEvent } from 'nuxt/server'
import { generateAuthTokens } from '#nuxt-aegis/server'
export async function loginUser(
event: RequestEvent,
user: Record<string, unknown>,
provider: string,
) {
const { accessToken, refreshToken } = await generateAuthTokens(event, user, provider)
if (refreshToken) {
const cookieConfig = useRuntimeConfig().nuxtAegis.tokenRefresh?.cookie
setRefreshTokenCookie(event, refreshToken, cookieConfig)
}
return { accessToken }
}getRefreshTokenFromCookie(event)
Get the refresh token from cookie.
Type Signature:
function getRefreshTokenFromCookie(event: RequestEvent): string | undefinedParameters:
| Parameter | Type | Description |
|---|---|---|
event | RequestEvent | Server request event |
Returns: string | undefined - Refresh token or undefined if not found
Example:
// server/routes/check-session.get.ts
export default defineEventHandler(async (event) => {
const refreshToken = getRefreshTokenFromCookie(event)
return {
hasSession: !!refreshToken
}
})Custom Claims Utilities
applyCustomClaims(user, customClaims)
Apply custom claims to a user object.
Type Signature:
function applyCustomClaims(
user: Record<string, unknown>,
customClaims: Record<string, unknown> | ((user: Record<string, unknown>) => Record<string, unknown> | Promise<Record<string, unknown>>)
): Promise<Record<string, unknown>>Parameters:
| Parameter | Type | Description |
|---|---|---|
user | Record<string, unknown> | User object |
customClaims | Record | Function | Custom claims object or callback |
Returns: Promise<Record<string, unknown>> - User with custom claims applied
Example:
// server/utils/enrichUser.ts
export async function enrichUserData(user: User) {
const enriched = await applyCustomClaims(user, async (u) => {
const profile = await db.getUserProfile(u.email)
return {
role: profile.role,
permissions: profile.permissions,
organizationId: profile.organizationId,
}
})
return enriched
}Complete Example
// server/routes/api/admin/users.get.ts
export default defineEventHandler(async (event) => {
// Require authentication
const user = await requireAuth(event)
// Check if user has admin role
if (user.role !== 'admin') {
throw createError({
status: 403,
message: 'Admin access required'
})
}
// Get all users
const users = await db.users.findMany()
return { users }
})// server/routes/api/posts.get.ts
export default defineEventHandler(async (event) => {
// Optional authentication
const user = await getAuthUser(event)
if (user) {
// Personalized posts for authenticated users
return await db.posts.findMany({
where: {
OR: [
{ public: true },
{ authorId: user.sub },
]
}
})
}
// Public posts only
return await db.posts.findMany({
where: { public: true }
})
})Error Handling
Handle authentication errors gracefully:
// server/routes/api/protected.get.ts
export default defineEventHandler(async (event) => {
try {
const user = await requireAuth(event)
return { data: 'protected' }
} catch (error) {
// Log error but don't expose details
console.error('Auth error:', error)
throw createError({
status: 401,
message: 'Authentication required'
})
}
})