Skip to content

Commit 485d81c

Browse files
committed
feat: expose useUsers composable
1 parent 96472ea commit 485d81c

File tree

8 files changed

+460
-351
lines changed

8 files changed

+460
-351
lines changed

docs/.vitepress/config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ export default defineConfig({
4747
{ text: 'Authorization (RBAC)', link: '/user-guide/authorization' },
4848
{ text: 'Password Reset', link: '/user-guide/password-reset' },
4949
{ text: 'Components', link: '/user-guide/components' },
50+
{ text: 'Composables', link: '/user-guide/composables' },
5051
{ text: 'Troubleshooting', link: '/user-guide/troubleshooting' }
5152
]
5253
},

docs/user-guide/authentication.md

Lines changed: 4 additions & 135 deletions
Original file line numberDiff line numberDiff line change
@@ -156,30 +156,7 @@ const handleLogin = async () => {
156156
</script>
157157
```
158158

159-
### Using the Authentication Composable
160-
161-
The module provides a `useAuthentication` composable for easier authentication management:
162-
163-
```vue
164-
<script setup>
165-
const { login, user, isAuthenticated } = useAuthentication()
166-
167-
const handleLogin = async (email, password) => {
168-
try {
169-
await login(email, password)
170-
console.log('Login successful:', user.value)
171-
await navigateTo('/dashboard')
172-
} catch (error) {
173-
console.error('Login failed:', error)
174-
}
175-
}
176-
177-
// Check if user is authenticated
178-
if (isAuthenticated.value) {
179-
console.log('User is logged in:', user.value)
180-
}
181-
</script>
182-
```
159+
For detailed usage of the `useAuthentication` composable, refer to the [Composables documentation](/user-guide/composables.md#useauthentication).
183160

184161
## Logout
185162

@@ -226,23 +203,7 @@ You can customize the appearance and behavior:
226203

227204
### Manual Logout
228205

229-
You can implement custom logout logic using the `useAuthentication` composable:
230-
231-
```vue
232-
<script setup>
233-
const { logout } = useAuthentication()
234-
235-
const handleLogout = async () => {
236-
try {
237-
await logout()
238-
console.log('Logged out successfully')
239-
await navigateTo('/login')
240-
} catch (error) {
241-
console.error('Logout failed:', error)
242-
}
243-
}
244-
</script>
245-
```
206+
For manual logout using the `useAuthentication` composable, refer to the [Composables documentation](/user-guide/composables.md#useauthentication).
246207

247208
### Direct API Call
248209

@@ -360,103 +321,11 @@ apiShield: {
360321

361322
## Checking Authentication Status
362323

363-
### In Components
364-
365-
```vue
366-
<template>
367-
<div>
368-
<div v-if="isAuthenticated">
369-
<p>Welcome, {{ user.name }}!</p>
370-
<NUsersLogoutLink />
371-
</div>
372-
<div v-else>
373-
<p>Please log in to continue</p>
374-
<NUsersLoginForm @success="handleLoginSuccess" />
375-
</div>
376-
</div>
377-
</template>
378-
379-
<script setup>
380-
const { user, isAuthenticated } = useAuthentication()
381-
382-
const handleLoginSuccess = (userData) => {
383-
console.log('User logged in:', userData)
384-
// Handle post-login logic
385-
}
386-
</script>
387-
```
388-
389-
### In Pages with Middleware
390-
391-
You can protect pages using the built-in authorization middleware:
392-
393-
```vue
394-
<!-- pages/dashboard.vue -->
395-
<template>
396-
<div>
397-
<h1>Dashboard</h1>
398-
<p>Welcome, {{ user.name }}!</p>
399-
</div>
400-
</template>
401-
402-
<script setup>
403-
// This page will automatically redirect to login if user is not authenticated
404-
definePageMeta({
405-
middleware: 'authorization'
406-
})
407-
408-
const { user } = useAuthentication()
409-
</script>
410-
```
324+
For checking authentication status using the `useAuthentication` composable, refer to the [Composables documentation](/user-guide/composables.md#useauthentication).
411325

412326
## Error Handling
413327

414-
### Handling Authentication Errors
415-
416-
```vue
417-
<script setup>
418-
const { login } = useAuthentication()
419-
420-
const handleLogin = async (email, password) => {
421-
try {
422-
await login(email, password)
423-
// Success - user is now authenticated
424-
} catch (error) {
425-
// Handle different types of errors
426-
if (error.statusCode === 401) {
427-
console.error('Invalid credentials')
428-
// Show "Invalid email or password" message
429-
} else if (error.statusCode === 400) {
430-
console.error('Missing email or password')
431-
// Show "Please fill in all fields" message
432-
} else {
433-
console.error('Login failed:', error.message)
434-
// Show generic error message
435-
}
436-
}
437-
}
438-
</script>
439-
```
440-
441-
### Network Error Handling
442-
443-
```vue
444-
<script setup>
445-
const handleLogin = async (email, password) => {
446-
try {
447-
await login(email, password)
448-
} catch (error) {
449-
if (error.name === 'FetchError') {
450-
console.error('Network error - please check your connection')
451-
// Show network error message
452-
} else {
453-
console.error('Authentication error:', error)
454-
// Show authentication error message
455-
}
456-
}
457-
}
458-
</script>
459-
```
328+
For error handling with the `useAuthentication` composable, refer to the [Composables documentation](/user-guide/composables.md#useauthentication).
460329

461330
## Security Best Practices
462331

docs/user-guide/authorization.md

Lines changed: 1 addition & 163 deletions
Original file line numberDiff line numberDiff line change
@@ -216,166 +216,4 @@ The default role is `user` if not specified.
216216

217217
## Programmatic Access Control
218218

219-
### usePublicPaths Composable
220-
221-
The module provides a `usePublicPaths` composable that allows you to programmatically determine which paths are accessible to users. This is useful for building dynamic navigation menus, API endpoint lists, or conditional UI elements.
222-
223-
```vue
224-
<script setup>
225-
import { usePublicPaths } from 'nuxt-users/composables'
226-
227-
const { getPublicPaths, getAccessiblePaths, isPublicPath, isAccessiblePath } = usePublicPaths()
228-
</script>
229-
```
230-
231-
#### Getting Public Paths
232-
233-
Get all paths that don't require authentication (accessible to everyone):
234-
235-
```js
236-
const publicPaths = getPublicPaths()
237-
console.log(publicPaths)
238-
/*
239-
{
240-
all: ['/login', '/reset-password', '/api/nuxt-users/session', '/about'],
241-
builtIn: {
242-
pages: ['/login', '/reset-password'],
243-
api: ['/api/nuxt-users/session', '/api/nuxt-users/password/forgot', '/api/nuxt-users/password/reset']
244-
},
245-
whitelist: ['/about', '/contact'], // From your nuxt.config.ts
246-
customPasswordResetPath: null,
247-
apiBasePath: '/api/nuxt-users'
248-
}
249-
*/
250-
```
251-
252-
#### Getting User-Accessible Paths
253-
254-
Get all paths accessible to the current authenticated user (includes public + role-based paths):
255-
256-
```js
257-
const accessiblePaths = getAccessiblePaths()
258-
console.log(accessiblePaths)
259-
/*
260-
For authenticated user with 'user' role:
261-
{
262-
all: ['/login', '/about', '/profile', '/dashboard', '/api/nuxt-users/me'],
263-
public: ['/login', '/reset-password', '/about'],
264-
roleBasedPaths: ['/profile', '/dashboard', '/api/nuxt-users/me'],
265-
userRole: 'user'
266-
}
267-
*/
268-
```
269-
270-
#### Checking Individual Paths
271-
272-
Check if specific paths are accessible:
273-
274-
```js
275-
// Check if a path is truly public (no auth required)
276-
console.log(isPublicPath('/login')) // true
277-
console.log(isPublicPath('/profile')) // false
278-
console.log(isPublicPath('/about')) // true (if whitelisted)
279-
280-
// Check if current user can access a path
281-
console.log(isAccessiblePath('/profile')) // true if user role allows
282-
console.log(isAccessiblePath('/admin')) // depends on user role
283-
console.log(isAccessiblePath('/api/users', 'POST')) // check specific HTTP method
284-
```
285-
286-
#### Practical Examples
287-
288-
**Building Dynamic Navigation:**
289-
290-
```vue
291-
<template>
292-
<nav>
293-
<NuxtLink
294-
v-for="item in visibleNavItems"
295-
:key="item.path"
296-
:to="item.path"
297-
>
298-
{{ item.label }}
299-
</NuxtLink>
300-
</nav>
301-
</template>
302-
303-
<script setup>
304-
const { isAccessiblePath } = usePublicPaths()
305-
306-
const allNavItems = [
307-
{ path: '/dashboard', label: 'Dashboard' },
308-
{ path: '/profile', label: 'Profile' },
309-
{ path: '/admin', label: 'Admin Panel' },
310-
{ path: '/about', label: 'About' }
311-
]
312-
313-
const visibleNavItems = computed(() =>
314-
allNavItems.filter(item => isAccessiblePath(item.path))
315-
)
316-
</script>
317-
```
318-
319-
**Conditional API Endpoints:**
320-
321-
```vue
322-
<script setup>
323-
const { isAccessiblePath } = usePublicPaths()
324-
325-
const availableActions = computed(() => {
326-
const actions = []
327-
328-
if (isAccessiblePath('/api/users', 'GET')) {
329-
actions.push({ label: 'View Users', endpoint: '/api/users', method: 'GET' })
330-
}
331-
332-
if (isAccessiblePath('/api/users', 'POST')) {
333-
actions.push({ label: 'Create User', endpoint: '/api/users', method: 'POST' })
334-
}
335-
336-
return actions
337-
})
338-
</script>
339-
```
340-
341-
**Role-Based UI Components:**
342-
343-
```vue
344-
<template>
345-
<div>
346-
<!-- Always visible for public paths -->
347-
<PublicContent v-if="isPublicPath($route.path)" />
348-
349-
<!-- Only visible if user can access admin routes -->
350-
<AdminPanel v-if="canAccessAdmin" />
351-
352-
<!-- Conditional buttons based on permissions -->
353-
<button v-if="canCreateUsers" @click="createUser">
354-
Create User
355-
</button>
356-
</div>
357-
</template>
358-
359-
<script setup>
360-
const { isPublicPath, isAccessiblePath } = usePublicPaths()
361-
362-
const canAccessAdmin = computed(() =>
363-
isAccessiblePath('/admin')
364-
)
365-
366-
const canCreateUsers = computed(() =>
367-
isAccessiblePath('/api/users', 'POST')
368-
)
369-
</script>
370-
```
371-
372-
### API Reference
373-
374-
| Method | Description | Returns |
375-
|--------|-------------|----------|
376-
| `getPublicPaths()` | Get all truly public paths (no auth required) | Object with categorized public paths |
377-
| `getAccessiblePaths()` | Get all paths accessible to current user | Object with public + role-based paths |
378-
| `isPublicPath(path)` | Check if a path is public | Boolean |
379-
| `isAccessiblePath(path, method?)` | Check if current user can access path | Boolean |
380-
381-
**Note:** Static assets (files with dots) and Nuxt internal routes (starting with `/_`) are always considered public and accessible.
219+
For programmatic access control using the `usePublicPaths` composable, refer to the [Composables documentation](/user-guide/composables.md#usepublicpaths).

docs/user-guide/components.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ The Nuxt Users module provides several Vue components to help you quickly implem
1212
| `NUsersList` | Paginated list of users with management actions |
1313
| `NUsersUserCard` | Individual user display card with edit/delete actions |
1414
| `NUsersUserForm` | Form for creating and editing user accounts |
15+
| `NUsersPasswordStrengthIndicator` | Displays real-time password strength feedback (uses `usePasswordValidation` composable) |
1516

1617
## Authentication Components
1718

@@ -226,9 +227,7 @@ const handleUserUpdated = () => {
226227
<span class="role-badge">{{ user.role }}</span>
227228
</div>
228229
<div class="user-actions">
229-
<button @click="handleEdit(user)" class="edit-btn">
230-
Edit
231-
</button>
230+
<button @click="handleEdit(user)">Edit</button>
232231
</div>
233232
</div>
234233
</template>

0 commit comments

Comments
 (0)