useXAuth
useXAuth
JWT authentication composable for the nuxt-x-auth-local layer. Connects to your own backend API — any server that accepts email/password and returns a JWT works. State (user, isLoading, emailSent) lives in Nuxt's useState so all component instances on the same page share the same reactive state without a Pinia store. On any 401 response, the composable automatically calls the refresh endpoint and retries the original request once.
Usage
const {
// State
user,
isLoading,
isAuthenticated,
emailSent,
// Core
login,
signup,
logout,
// Password management
forgotPassword,
resetPassword,
changePassword,
// Token / session
refreshToken,
getCurrentUser,
getToken,
getAuthHeaders,
resetState,
config,
} = useXAuth()
Returns
State
| Key | Type | Description |
|---|---|---|
user | Ref<AuthUser | null> | The currently authenticated user. Shared via useState — all instances on the same page are in sync. |
isLoading | Ref<boolean> | true while any auth operation or token refresh is in progress. Shared via useState. |
isAuthenticated | ComputedRef<boolean> | true when user is not null. |
emailSent | Ref<boolean> | true after forgotPassword succeeds. Always shows success to prevent email enumeration. |
Auth Methods
| Key | Type | Description |
|---|---|---|
login | (email: string, password: string) => Promise<AuthUser | null> | POST to loginEndpoint. Stores tokens in cookies and sets user. |
signup | (email: string, password: string) => Promise<AuthUser | null> | POST to signupEndpoint. Returns the new user on success. |
logout | () => Promise<true> | POST to logoutEndpoint. Clears cookies and resets user. Redirects to redirects.afterLogout. |
forgotPassword | (email: string) => Promise<boolean> | POST to forgotPasswordEndpoint. Sets emailSent = true regardless of whether the email exists. |
resetPassword | (token: string, newPassword: string) => Promise<true | { error: string }> | POST to resetPasswordEndpoint with the token from the email link. |
changePassword | (currentPassword: string, newPassword: string) => Promise<true | { error: string }> | POST to changePasswordEndpoint. Requires an active session. |
Token / Session
| Key | Type | Description |
|---|---|---|
refreshToken | () => Promise<AuthTokens | null> | POST to refreshEndpoint with the stored refresh cookie. Returns new tokens or null if refresh fails (cookies are then cleared). |
getCurrentUser | () => Promise<AuthUser | null> | GET to userEndpoint with Bearer header. Updates user. Automatically called after login. |
getToken | () => string | null | Synchronously reads the access token from the cookie. Returns null if not present. |
getAuthHeaders | () => Record<string, string> | Synchronously returns { Authorization: 'Bearer <token>' }. Returns {} if no token. |
Utilities
| Key | Type | Description |
|---|---|---|
resetState | () => void | Resets emailSent to false. |
config | ComputedRef<AuthConfig> | Reactive reference to the full xAuth app config from app.config.ts. |
AuthUser Shape
{
id: string
email: string
name: string
avatar?: string
emailVerified: boolean
metadata?: Record<string, any>
}
User data is normalized from your API response via fieldMapper, which tries common field variants (id/sub/user_id, name/displayName/full_name, etc.) automatically.
Expected API Response Shapes
Login / Signup:
{ "accessToken": "eyJ...", "refreshToken": "eyJ..." }
Also accepts token as an alias for accessToken.
Current user (/auth/me):
{ "user": { "id": "1", "email": "user@example.com", "name": "Jane" } }
Or a flat object: { "id": "1", "email": "...", "name": "..." }.
Token refresh (/auth/refresh):
{ "accessToken": "eyJ...", "refreshToken": "eyJ..." }
Automatic Token Refresh
On any 401 response, fetchApi (the internal request helper) calls refreshEndpoint with the stored refresh cookie and retries the original request once. If refresh fails, all auth cookies are cleared. Disable this behavior by setting tokens.hasRefresh: false in app.config.ts.
Security
All redirect targets are validated to be relative paths starting with /. Protocol-relative (//) and absolute URLs are silently replaced with / to prevent open redirect attacks.
Examples
// Login
const user = await login('user@example.com', 'password')
// Protect an API call (synchronous — no await needed)
const headers = getAuthHeaders()
// { Authorization: 'Bearer eyJ...' }
const data = await $fetch('/api/protected', { headers })
// Change password
const result = await changePassword('oldPass', 'newPass')
if (result !== true) console.error(result.error)
// Reset password from email link
const result = await resetPassword(route.query.token as string, newPassword)
<script setup>
const { user, isAuthenticated, logout } = useXAuth()
</script>
<template>
<div v-if="isAuthenticated">
Welcome, {{ user?.name }}
<UButton @click="logout">Sign Out</UButton>
</div>
<XAuthLogin v-else />
</template>
AI Context
composable: useXAuth
package: "@xenterprises/nuxt-x-auth-local"
use-when: >
All authentication operations in a Nuxt app using a self-hosted JWT backend.
Works with any API that accepts email/password and returns a JWT. State is
shared via useState — no Pinia required. getToken and getAuthHeaders are
synchronous for simple API call protection. Automatic 401 token refresh means
callers never need to handle token expiry manually. Configure all endpoints
via runtimeConfig.public.localAuth.
