Team-based authentication is built into Nuxt Crouton, automatically scoping all data and API calls to the current team context.
All generated collections are team-scoped by default:
teamId (text, required) - References the team/organizationowner (text, required) - References the user who owns the recordcreatedBy (text) - References the user who created the recordteamId and owner from the authenticated sessionresolveTeamAndCheckMembershipteamId or owner in your schema JSON files. The generator adds these automatically, and manual definitions will cause duplicate key errors.See Schema Format - Auto-Generated Fields for details.Team authentication requires @fyit/crouton-auth:
pnpm add @fyit/crouton-auth
// nuxt.config.ts
export default defineNuxtConfig({
extends: [
'@fyit/crouton',
'@fyit/crouton-auth'
]
})
Use useTeamContext() to access the current team:
<script setup lang="ts">
const { teamId, teamSlug } = useTeamContext()
// All API calls include team context
const { items } = await useCollectionQuery('shopProducts')
// → Fetches /api/teams/[teamId]/shop-products
</script>
useCollectionQuery patterns, see Querying Data.Generated API endpoints use @fyit/crouton-auth/server/utils/team for team authentication:
// Generated: server/api/teams/[team]/shop-products/index.get.ts
import { resolveTeamAndCheckMembership } from '@fyit/crouton-auth/server/utils/team'
export default defineEventHandler(async (event) => {
const { team, user } = await resolveTeamAndCheckMembership(event)
// Query scoped to team
const products = await db
.select()
.from(shopProducts)
.where(eq(shopProducts.teamId, team.id))
return products
})
Team-scoped API routes follow the pattern:
/api/teams/[team]/{layer}-{collection}/
For example:
/api/teams/abc123/shop-products/ - List products for team/api/teams/abc123/shop-products/xyz789 - Get/update/delete specific productAllow users to switch between teams with automatic query refetching:
<script setup lang="ts">
const { currentTeam, teams, switchTeam } = useTeam()
const handleSwitchTeam = async (teamId: string) => {
await switchTeam(teamId)
// All queries auto-refetch for new team!
}
</script>
<template>
<USelectMenu
v-model="currentTeam"
:options="teams"
@update:model-value="handleSwitchTeam"
/>
</template>
@fyit/crouton-auth[team]teamId is injected into all queries and mutations