Talon Auth integrates with Nuxt using a shared client plugin, a server plugin for SSR, and the <talon-login> web component for the login UI. The access token is automatically stored in a same-site cookie so server-side rendering always has access to it.
Install the package:
npm install talon-auth
Add your app ID, API URL, and cookie name to nuxt.config.ts:
export default defineNuxtConfig({
runtimeConfig: {
public: {
talon: {
appId: process.env.TALON_APP_ID,
apiUrl: 'https://api.talon.codes',
cookie: 'talon-auth',
},
},
},
vue: {
compilerOptions: {
isCustomElement: (tag) => tag === 'talon-login',
},
},
})
Create plugins/talon.client.ts to instantiate the shared auth client and provide it to the app. The cookie option makes the client automatically store the access token in a same-site cookie after every token fetch, and clear it on logout.
// plugins/talon.client.ts
import { createClient } from 'talon-auth'
export default defineNuxtPlugin(() => {
const { appId, apiUrl, cookie } = useRuntimeConfig().public.talon
return {
provide: {
talonClient: createClient({ appId, api: apiUrl, cookie }),
},
}
})
Create plugins/talon.server.ts to verify the cookie on each SSR request and populate the user state before the page renders:
// plugins/talon.server.ts
import { createVerifier } from 'talon-auth'
export default defineNuxtPlugin(async () => {
const { appId, cookie: cookieName } = useRuntimeConfig().public.talon
const token = useCookie(cookieName).value
if (!token) return
try {
const { user } = await createVerifier({ appId }).verify(token)
useState('talon-user').value = user
} catch {}
})
Add composables for user state and token access. getTalonAuthToken reads from the cookie on the server and calls getAccessToken() on the client, which handles token refresh and keeps the cookie up to date:
// composables/use-talon.ts
import type { TalonAuthUser } from 'talon-auth'
export const useTalonUser = () =>
readonly(useState<TalonAuthUser | null>('talon-user', () => null))
export const useTalonClient = () => useNuxtApp().$talonClient
export function getTalonAuthToken() {
if (import.meta.server) {
const cookieName = useRuntimeConfig().public.talon.cookie
return useCookie<string | null>(cookieName).value ?? null
}
return useTalonClient().getAccessToken()
}
Import the web component client-side only and pass the shared client via :authClient (camelCase is required — Vue must set this as a DOM property, not an HTML attribute):
<script setup lang="ts">
if (import.meta.client) {
await import('talon-auth/login')
}
const user = useTalonUser()
async function onLogin() {
const userState = useState('talon-user')
try {
userState.value = await useTalonClient().getUser()
} catch {
userState.value = null
}
}
</script>
<template>
<ClientOnly>
<talon-login :authClient="$talonClient" @login="onLogin" />
</ClientOnly>
<p v-if="user">Hello, {{ user.email }}</p>
</template>
Call logout() on the shared client to clear the IndexedDB token and the cookie, then clear the user state:
await useTalonClient().logout()
useState('talon-user').value = null
navigateTo('/')
Use getTalonAuthToken() in any function that needs to attach a Bearer token to outgoing requests. It works on both the server (reads the cookie) and the client (calls getAccessToken()):
const token = await getTalonAuthToken()
const data = await $fetch('/api/protected', {
headers: token ? { Authorization: `Bearer ${token}` } : {},
})