useAuth
The three things a page ever does with a session: log in, log out, refresh. Each one updates the store, the abilities and the route together.
Import
ts
import { bootstrapAuth, useAuth } from '@modules/auth/composables/useAuth'Signature
ts
function useAuth(): {
login: (creds: LoginCredentials) => Promise<void>
logout: () => Promise<void>
refreshSession: () => Promise<boolean>
}
async function bootstrapAuth(): Promise<void>Returns
| Member | Type | Description |
|---|---|---|
login | (creds) => Promise<void> | Posts the credentials, stores the user and permissions, updates CASL, redirects, toasts a welcome. Rejects on failure so the form can show it. |
logout | () => Promise<void> | Calls the API, then resets the store, clears abilities and returns to /auth/login. |
refreshSession | () => Promise<boolean> | true when the session was renewed, false when it was not. Never rejects. |
bootstrapAuth
A standalone export, not part of the returned object. It re-hydrates the session from the HTTP-only cookie and is safe to call before app.mount(), because it touches only the store and CASL — no router, no route.
Example
vue
<script setup lang="ts">
import { useAuth } from '@modules/auth/composables/useAuth'
import { ref } from 'vue'
const { login } = useAuth()
const email = ref('admin@example.com')
const password = ref('')
const failed = ref(false)
const busy = ref(false)
async function submit() {
failed.value = false
busy.value = true
try {
await login({ email: email.value, password: password.value })
}
catch {
failed.value = true
}
finally {
busy.value = false
}
}
</script>
<template>
<form class="space-y-3" @submit.prevent="submit()">
<input v-model="email" type="email" autocomplete="username">
<input v-model="password" type="password" autocomplete="current-password">
<p v-if="failed">
Those details did not match.
</p>
<button type="submit" :disabled="busy">
Sign in
</button>
</form>
</template>And in main.ts:
ts
import { bootstrapAuth } from '@modules/auth/composables/useAuth'
import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App)
await bootstrapAuth()
app.mount('#app')Notes
- The three differ on purpose in how they fail.
loginlets the caller catch, because a login form has to show the error.refreshSessionandbootstrapAuthswallow, because they run where there is nobody to tell.logoutresets local state in afinally, so a failed server call still signs you out locally. loginredirects toroute.query.redirect, falling back to/dashboard. That is how the router guard returns a reader to the page they asked for.- The router and route are resolved at the top of
useAuth, before anyawait. Read after one,inject()warns that the component instance is no longer current. bootstrapAuth's probe opts out of the refresh interceptor. A logged-out401is the normal answer there; letting it trigger refresh-and-redirect would reload the page and re-run the bootstrap forever.bootstrapAuthalso kicks off the tenant palette throughuseThemeProvider, unconditionally and fire-and-forget, so a slow/themenever blocks first paint.- Permissions land in CASL through
updateAbility, which is what makesusePermissionsandv-permissionanswer correctly straight afterwards.
Related
- Auth and permissions — the guard, the mock mode and the routes.
usePermissions— asking what the user may do.v-permission— the template-level gate.useApiError— what a failed call looks like to the reader.