useLoginCheck()

useLoginCheck() is the core auth-gating composable. Call it before a business action; when the user isn't logged in, it auto-guides them per the mode (page redirect or dialog) and returns false. When logged in, it returns true immediately.

Signature: useLoginCheck(options?): Promise<boolean> — returns a Promise directly (true if logged in, false otherwise); it does NOT return an object with isLoggedIn / checkLogin.

Basic usage

<script setup lang="ts">
async function submitComment() {
  // Not logged in → redirects to /login?redirect=current-path; logged in → returns true
  if (!(await useLoginCheck())) return

  await request('/comment/add', { body: { content: text.value } })
}
</script>

For lightweight desktop interactions like Like / Favorite where you don't want to navigate away, use the dialog form:

<script setup lang="ts">
const { open } = useLoginDialog()

async function onLike() {
  if (!(await useLoginCheck({ mode: 'dialog', openDialog: open }))) return

  await request('/like/toggle', { body: { id } })
}
</script>

Force login without returning to original page

For sensitive flows (e.g. after changing email, jump to homepage to confirm), use redirectBack: false:

await useLoginCheck({ redirectBack: false })

Parameters

ParamTypeDefaultDescription
mode'page' | 'dialog''page'Guidance for unauthenticated users: page redirects to /login; dialog calls openDialog to open a modal
redirectBackbooleantrueWhether to append ?redirect=current-path (only effective when mode: 'page')
openDialog() => void—Required when mode: 'dialog' — function that opens the dialog. Typically pass useLoginDialog()'s open

Return

  • Promise<boolean> — true = logged in, proceed with the action; false = not logged in, the guidance has already happened (redirect or dialog), caller should early-return.

This composable returns Promise<boolean> directly, not an object. Current signature: see src/runtime/composables/useLoginCheck.ts.

Relationship to global reactive login state

To check "is the user currently logged in" reactively, use useUserStore()'s isLoggedIn ref (cookie-synced across tabs):

<template>
  <div v-if="userStore.isLoggedIn">
    <UserProfile />
  </div>
  <div v-else>
    <NuxtLink to="/login">Please log in to continue</NuxtLink>
  </div>
</template>

<script setup lang="ts">
const userStore = useUserStore()
</script>

useLoginCheck() is a one-shot side effect ("guide if not logged in"); don't await it in templates as reactive state.

Relationship to route guards

The framework's built-in login.global middleware does NOT call useLoginCheck() — it reads userStore.isLoggedIn directly (lighter, no side effects). Guarded paths are configured in nuxt.config.ts's swiftConfig.auth.guardedPaths:

// nuxt.config.ts
export default defineNuxtConfig({
  swiftConfig: {
    auth: {
      guardedPaths: ['/mine', '/profile', '/settings'],
      guestPaths: ['/login', '/register'],
    },
  },
})

useLoginCheck() is for fine-grained business-side guidance (check before a specific action), not a middleware replacement.

Caveats

  • Must be awaited, or downstream logic runs before login finishes (Rule UL-001) — it returns Promise<boolean> (true = logged in / false = not logged in and already redirected to the login page or opened the login dialog). Skipping await leads to a null userInfo, unauthenticated backend calls, or the odd "error first, redirect second" sequence. Canonical form: if (!(await useLoginCheck())) return.
  • TypeScript's no-floating-promises only catches part of it — nested calls inside conditionals, or forgetting async on the enclosing function, still slip through. Give it a second look as you write.
  • Semantically different from useLoginDialog() — this one decides (logged-in users pass straight through); useLoginDialog() only toggles dialog visibility and decides nothing (see Rule ULD-001). For "block only when logged out, and wait for the outcome", always use this one.